<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link href="../css/main.css" media="all" rel="stylesheet" type="text/css" />
<link href="../css/highlight.css" media="all" rel="stylesheet" type="text/css" />
<link href="../css/print.css" media="print" rel="stylesheet" type="text/css" />
<title>第10章 - フォーム</title>
</head>

<body>
<div class="navigation">

<table width="100%">
<tr>
<td width="40%" align="left"><a href="09-Links-and-the-Routing-System.html">前の章</a></td>
<td width="20%" align="center"><a href="index.html">ホーム</a></td>
<td width="40%" align="right"><a href="11-Ajax-Integration.html">次の章</a></td>
</tr>
</table>
<hr/>
</div>

<div>
<a name="chapter.10.forms" id="chapter.10.forms"></a><h1>第10章 - フォーム</h1>

<blockquote class="caution"><p>
  この章ではsymfony 1.0でフォームを実装する方法を説明しています。互換性のためにadminジェネレーターの機能はまだこのシステムを利用するので、symfony 1.2でもこの章の情報も価値があります。しかしながら、symfony 1.2で新しいプロジェクトを始めるのであれば、新しいフォームフレームワークの詳細について"symfony 
  Forms in Action"の本も読むべきです。</p>
</blockquote>

<p>テンプレートを書くとき、開発者の多くの時間はフォーム(form)に費やされます。このことにもかかわらず、一般的にフォームは貧弱に設計されます。デフォルト値、整形、検証、再投入と一般的なフォームの扱いなど多くのことに注意を払うことが必要なので、開発者のなかにはプロセスにおけるいくつかの重要な詳細事項を大まかにしか見ない人がいます。というわけで、symfonyはこのトピックに対して特別な注意を払うことにします。この章ではフォームの開発速度を上げる一方で、これらの多くの要件を自動化するツールについて説明します。</p>

<ul>
<li>フォームヘルパーは、とりわけ日付、ドロップダウンのリスト、とリッチテキストなどの複雑な要素に対して、テンプレートのなかでフォームを速く書く方法を提供します。</li>
<li>フォームがオブジェクトのプロパティを編集することに徹する場合、オブジェクトフォームヘルパーを利用することでテンプレートの編集作業が速くなります。</li>
<li>YAMLバリデーションファイルはフォームのバリデーションと再投入を円滑にします。</li>
<li>バリデーターは入力をバリデートするために必要なコードをまとめます。symfonyはもっとも共通なニーズのためのバリデーターを搭載します。またカスタムバリデーターを追加することはとても簡単です。</li>
</ul>

<div class="toc">
<dl>
<dt><a href="#form.helpers">10.1. フォームヘルパー</a></dt>
<dd><dl>
<dt><a href="#main.form.tag">10.1.1. メインのフォームタグ</a></dt>
<dt><a href="#standard.form.elements">10.1.2. 標準のフォーム要素</a></dt>
<dt><a href="#date.input.widgets">10.1.3. 日付入力ウィジェット</a></dt>
<dt><a href="#rich.text.editing">10.1.4. リッチなテキスト編集機能</a></dt>
<dt><a href="#country.language.and.currency.selection">10.1.5. 国、言語と通貨の選択</a></dt>
</dl></dd>
<dt><a href="#form.helpers.for.objects">10.2. オブジェクトのためのフォームヘルパー</a></dt>
<dd><dl>
<dt><a href="#populating.dropdown.lists.with.objects">10.2.1. ドロップダウンをオブジェクトで投入する</a></dt>
<dt><a href="#creating.a.dropdown.list.based.on.a.foreign.key.column">10.2.2. 外部キーのカラムをもとにドロップダウンリストを作る</a></dt>
<dt><a href="#updating.objects">10.2.3. オブジェクトを更新する</a></dt>
</dl></dd>
<dt><a href="#form.validation">10.3. フォームのバリデーション</a></dt>
<dd><dl>
<dt><a href="#validators">10.3.1. バリデーター</a></dt>
<dt><a href="#validation.file">10.3.2. バリデーションファイル</a></dt>
<dt><a href="#redisplaying.the.form">10.3.3. フォームを再表示する</a></dt>
<dt><a href="#displaying.the.error.messages.in.the.form">10.3.4. フォームのなかでエラーメッセージを表示する</a></dt>
<dt><a href="#repopulating.the.form">10.3.5. フォームを再投入する</a></dt>
<dt><a href="#standard.symfony.validators">10.3.6. symfonyの標準バリデーター </a></dt>
<dd><dl>
<dt><a href="#string.validator">10.3.6.1. 文字列バリデーター</a></dt>
<dt><a href="#number.validator">10.3.6.2. 数字バリデーター</a></dt>
<dt><a href="#email.validator">10.3.6.3. Eメールバリデーター</a></dt>
<dt><a href="#url.validator">10.3.6.4. URLバリデーター</a></dt>
<dt><a href="#regular.expression.validator">10.3.6.5. 正規表現バリデーター</a></dt>
<dt><a href="#compare.validator">10.3.6.6. 比較バリデーター</a></dt>
<dt><a href="#propel/doctrine.unique.validators">10.3.6.7. Propel/Doctrine独自のバリデーター </a></dt>
<dt><a href="#file.validator">10.3.6.8. ファイルバリデーター</a></dt>
<dt><a href="#callback.validator">10.3.6.9. コールバックバリデーター</a></dt>
<dt><a href="#date.validator">10.3.6.10. 日付バリデーター</a></dt>
</dl></dd>
<dt><a href="#named.validators">10.3.7. 名前つきバリデーター</a></dt>
<dt><a href="#restricting.the.validation.to.a.method">10.3.8. メソッドへのバリデーションを制限する</a></dt>
<dt><a href="#what.does.a.validation.file.look.like">10.3.9. バリデーションファイルはどのようになるのか？</a></dt>
</dl></dd>
<dt><a href="#complex.validation">10.4. 複雑なバリデーション</a></dt>
<dd><dl>
<dt><a href="#creating.a.custom.validator">10.4.1. カスタムバリデーターを作成する</a></dt>
<dt><a href="#using.array.syntax.for.form.fields">10.4.2. フォームフィールドに対して配列構文を使う</a></dt>
<dt><a href="#executing.a.validator.on.an.empty.field">10.4.3. 空のフィールド上でバリデーターを実行する</a></dt>
</dl></dd>
<dt><a href="#summary">10.5. まとめ</a></dt>
</dl>
</div>
<a name="form.helpers" id="form.helpers"></a><h2>フォームヘルパー</h2>

<p>テンプレートによって、フォーム要素のHTMLタグがPHPコードに混ざることはよくあることです。symfonyのフォームヘルパーはこのタスクをシンプルにして<code>&lt;input&gt;</code>タグのあいだで<code>&lt;?php echo</code>のタグを繰り返し展開することを避けることを目的としています。</p>

<a name="main.form.tag" id="main.form.tag"></a><h3>メインのフォームタグ</h3>

<p>以前の章で説明したように、フォームを作るには<code>form_tag()</code>ヘルパーを使わなければなりません。このヘルパーがパラメーターとして渡されたアクションをルーティングURLに変換するからです。2番目の引数は追加オプションをサポートします。たとえば、デフォルトの<code>method</code>を変更するには、デフォルトの<code>enctype</code>を変更するか、もしくはほかの属性を指定します。リスト10-1は例を示しています。</p>

<p>リスト10-1 - <code>form_tag()</code>ヘルパー</p>

<pre class="php"><span class="kw2">&lt;?php</span> <span class="kw1">echo</span> form_tag<span class="br0">&#40;</span><span class="st_h">'test/save'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
 =&gt; &lt;form method=&quot;post&quot; action=&quot;/path/to/save&quot;&gt;
&nbsp;
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> form_tag<span class="br0">&#40;</span><span class="st_h">'test/save'</span><span class="sy0">,</span> <span class="st_h">'method=get multipart=true class=simpleForm'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
 =&gt; &lt;form method=&quot;get&quot; enctype=&quot;multipart/form-data&quot; class=&quot;simpleForm&quot;action=&quot;/path/to/save&quot;&gt;</pre>

<p>フォームヘルパーを閉じる必要がないので、ソースコードのなかできれいに見えなくても、HTMLの<code>&lt;/form&gt;</code>を使うべきです。</p>

<a name="standard.form.elements" id="standard.form.elements"></a><h3>標準のフォーム要素</h3>

<p>デフォルトでは、フォームヘルパーによって、フォームのなかのそれぞれの要素はname属性から推測されるid属性に渡されます。これは便利なだけの規約ではありません。標準のフォームヘルパーとそれらのオプションの全リストに関してはリスト10-2をご覧ください。</p>

<p>リスト10-2 - 標準のフォームヘルパーの構文</p>

<pre class="php">// テキストフィールド(入力)
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> input_tag<span class="br0">&#40;</span><span class="st_h">'name'</span><span class="sy0">,</span> <span class="st_h">'default value'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
 =&gt; &lt;input type=&quot;text&quot; name=&quot;name&quot; id=&quot;name&quot; value=&quot;default value&quot; /&gt;
&nbsp;
// すべてのフォームヘルパーは追加オプションのパラメーターを受けとる
// これによってカスタム属性を生成タグに追加できる
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> input_tag<span class="br0">&#40;</span><span class="st_h">'name'</span><span class="sy0">,</span> <span class="st_h">'default value'</span><span class="sy0">,</span> <span class="st_h">'maxlength=20'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
 =&gt; &lt;input type=&quot;text&quot; name=&quot;name&quot; id=&quot;name&quot; value=&quot;default value&quot; maxlength=&quot;20&quot; /&gt;
&nbsp;
// 長いテキストフィールド(テキストエリア)
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> textarea_tag<span class="br0">&#40;</span><span class="st_h">'name'</span><span class="sy0">,</span> <span class="st_h">'default content'</span><span class="sy0">,</span> <span class="st_h">'size=10x20'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
 =&gt; &lt;textarea name=&quot;name&quot; id=&quot;name&quot; cols=&quot;10&quot; rows=&quot;20&quot;&gt;
      default content
    &lt;/textarea&gt;
&nbsp;
// チェックボックス
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> checkbox_tag<span class="br0">&#40;</span><span class="st_h">'single'</span><span class="sy0">,</span> <span class="nu0">1</span><span class="sy0">,</span> <span class="kw4">true</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> checkbox_tag<span class="br0">&#40;</span><span class="st_h">'driverslicense'</span><span class="sy0">,</span> <span class="st_h">'B'</span><span class="sy0">,</span> <span class="kw4">false</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
 =&gt; &lt;input type=&quot;checkbox&quot; name=&quot;single&quot; id=&quot;single&quot; value=&quot;1&quot; checked=&quot;checked&quot; /&gt;
    &lt;input type=&quot;checkbox&quot; name=&quot;driverslicense&quot; id=&quot;driverslicense&quot; value=&quot;B&quot; /&gt;
&nbsp;
// ラジオボタン
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> radiobutton_tag<span class="br0">&#40;</span><span class="st_h">'status[]'</span><span class="sy0">,</span> <span class="st_h">'value1'</span><span class="sy0">,</span> <span class="kw4">true</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> radiobutton_tag<span class="br0">&#40;</span><span class="st_h">'status[]'</span><span class="sy0">,</span> <span class="st_h">'value2'</span><span class="sy0">,</span> <span class="kw4">false</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
 =&gt; &lt;input type=&quot;radio&quot; name=&quot;status[]&quot; id=&quot;status_value1&quot; value=&quot;value1&quot; checked=&quot;checked&quot; /&gt;
    &lt;input type=&quot;radio&quot; name=&quot;status[]&quot; id=&quot;status_value2&quot; value=&quot;value2&quot; /&gt;
&nbsp;
// ドロップダウンリスト(選択)
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> select_tag<span class="br0">&#40;</span><span class="st_h">'payment'</span><span class="sy0">,</span>
  <span class="st_h">'&lt;option selected=&quot;selected&quot;&gt;Visa&lt;/option&gt;
   &lt;option&gt;Eurocard&lt;/option&gt;
   &lt;option&gt;Mastercard&lt;/option&gt;'</span><span class="br0">&#41;</span>
<span class="sy1">?&gt;</span>
 =&gt; &lt;select name=&quot;payment&quot; id=&quot;payment&quot;&gt;
      &lt;option selected=&quot;selected&quot;&gt;Visa&lt;/option&gt;
      &lt;option&gt;Eurocard&lt;/option&gt;
      &lt;option&gt;Mastercard&lt;/option&gt;
    &lt;/select&gt;
&nbsp;
// 選択タグのためのオプションのリスト
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> options_for_select<span class="br0">&#40;</span><span class="kw3">array</span><span class="br0">&#40;</span><span class="st_h">'Visa'</span><span class="sy0">,</span> <span class="st_h">'Eurocard'</span><span class="sy0">,</span> <span class="st_h">'Mastercard'</span><span class="br0">&#41;</span><span class="sy0">,</span> <span class="nu0">0</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
 =&gt; &lt;option value=&quot;0&quot; selected=&quot;selected&quot;&gt;Visa&lt;/option&gt;
    &lt;option value=&quot;1&quot;&gt;Eurocard&lt;/option&gt;
    &lt;option value=&quot;2&quot;&gt;Mastercard&lt;/option&gt;
&nbsp;
// オプションのリストと結びつけられたドロップダウンヘルパーオプションのリスト
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> select_tag<span class="br0">&#40;</span><span class="st_h">'payment'</span><span class="sy0">,</span> options_for_select<span class="br0">&#40;</span><span class="kw3">array</span><span class="br0">&#40;</span>
  <span class="st_h">'Visa'</span><span class="sy0">,</span>
  <span class="st_h">'Eurocard'</span><span class="sy0">,</span>
  <span class="st_h">'Mastercard'</span>
<span class="br0">&#41;</span><span class="sy0">,</span> <span class="nu0">0</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
 =&gt; &lt;select name=&quot;payment&quot; id=&quot;payment&quot;&gt;
      &lt;option value=&quot;0&quot; selected=&quot;selected&quot;&gt;Visa&lt;/option&gt;
      &lt;option value=&quot;1&quot;&gt;Eurocard&lt;/option&gt;
      &lt;option value=&quot;2&quot;&gt;Mastercard&lt;/option&gt;
    &lt;/select&gt;
&nbsp;
// オプション名を指定するため、連想配列を使う
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> select_tag<span class="br0">&#40;</span><span class="st_h">'name'</span><span class="sy0">,</span> options_for_select<span class="br0">&#40;</span><span class="kw3">array</span><span class="br0">&#40;</span>
  <span class="st_h">'Steve'</span>  <span class="sy0">=&gt;</span> <span class="st_h">'Steve'</span><span class="sy0">,</span>
  <span class="st_h">'Bob'</span>    <span class="sy0">=&gt;</span> <span class="st_h">'Bob'</span><span class="sy0">,</span>
  <span class="st_h">'Albert'</span> <span class="sy0">=&gt;</span> <span class="st_h">'Albert'</span><span class="sy0">,</span>
  <span class="st_h">'Ian'</span>    <span class="sy0">=&gt;</span> <span class="st_h">'Ian'</span><span class="sy0">,</span>
  <span class="st_h">'Buck'</span>   <span class="sy0">=&gt;</span> <span class="st_h">'Buck'</span>
<span class="br0">&#41;</span><span class="sy0">,</span> <span class="st_h">'Ian'</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
 =&gt; &lt;select name=&quot;name&quot; id=&quot;name&quot;&gt;
      &lt;option value=&quot;Steve&quot;&gt;Steve&lt;/option&gt;
      &lt;option value=&quot;Bob&quot;&gt;Bob&lt;/option&gt;
      &lt;option value=&quot;Albert&quot;&gt;Albert&lt;/option&gt;
      &lt;option value=&quot;Ian&quot; selected=&quot;selected&quot;&gt;Ian&lt;/option&gt;
      &lt;option value=&quot;Buck&quot;&gt;Buck&lt;/option&gt;
    &lt;/select&gt;
&nbsp;
// 複数の選択肢を持つドロップダウンリスト(選択された値は配列が可能)
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> select_tag<span class="br0">&#40;</span><span class="st_h">'payment'</span><span class="sy0">,</span> options_for_select<span class="br0">&#40;</span>
  <span class="kw3">array</span><span class="br0">&#40;</span><span class="st_h">'Visa'</span> <span class="sy0">=&gt;</span> <span class="st_h">'Visa'</span><span class="sy0">,</span> <span class="st_h">'Eurocard'</span> <span class="sy0">=&gt;</span> <span class="st_h">'Eurocard'</span><span class="sy0">,</span> <span class="st_h">'Mastercard'</span> <span class="sy0">=&gt;</span> <span class="st_h">'Mastercard'</span><span class="br0">&#41;</span><span class="sy0">,</span>
  <span class="kw3">array</span><span class="br0">&#40;</span><span class="st_h">'Visa'</span><span class="sy0">,</span> <span class="st_h">'Mastercard'</span><span class="br0">&#41;</span><span class="sy0">,</span>
<span class="br0">&#41;</span><span class="sy0">,</span> <span class="kw3">array</span><span class="br0">&#40;</span><span class="st_h">'multiple'</span> <span class="sy0">=&gt;</span> <span class="kw4">true</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
&nbsp;
 =&gt; &lt;select name=&quot;payment[]&quot; id=&quot;payment&quot; multiple=&quot;multiple&quot;&gt;
      &lt;option value=&quot;Visa&quot; selected=&quot;selected&quot;&gt;Visa&lt;/option&gt;
      &lt;option value=&quot;Eurocard&quot;&gt;Eurocard&lt;/option&gt;
      &lt;option value=&quot;Mastercard&quot;&gt;Mastercard&lt;/option&gt;
    &lt;/select&gt;
// 複数の選択肢を持つドロップダウンリスト(選択された値は配列が可能)
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> select_tag<span class="br0">&#40;</span><span class="st_h">'payment'</span><span class="sy0">,</span> options_for_select<span class="br0">&#40;</span>
  <span class="kw3">array</span><span class="br0">&#40;</span><span class="st_h">'Visa'</span> <span class="sy0">=&gt;</span> <span class="st_h">'Visa'</span><span class="sy0">,</span> <span class="st_h">'Eurocard'</span> <span class="sy0">=&gt;</span> <span class="st_h">'Eurocard'</span><span class="sy0">,</span> <span class="st_h">'Mastercard'</span> <span class="sy0">=&gt;</span> <span class="st_h">'Mastercard'</span><span class="br0">&#41;</span><span class="sy0">,</span>
  <span class="kw3">array</span><span class="br0">&#40;</span><span class="st_h">'Visa'</span><span class="sy0">,</span> <span class="st_h">'Mastercard'</span><span class="br0">&#41;</span>
<span class="br0">&#41;</span><span class="sy0">,</span> <span class="st_h">'multiple=multiple'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
 =&gt; &lt;select name=&quot;payment[]&quot; id=&quot;payment&quot; multiple=&quot;multiple&quot;&gt;
      &lt;option value=&quot;Visa&quot; selected=&quot;selected&quot;&gt;Visa&lt;/option&gt;
      &lt;option value=&quot;Eurocard&quot;&gt;Eurocard&lt;/option&gt;
      &lt;option value=&quot;Mastercard&quot; selected=&quot;selected&quot;&gt;Mastercard&lt;/option&gt;
    &lt;/select&gt;
&nbsp;
// アップロードファイルフィールド
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> input_file_tag<span class="br0">&#40;</span><span class="st_h">'name'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
 =&gt; &lt;input type=&quot;file&quot; name=&quot;name&quot; id=&quot;name&quot; value=&quot;&quot; /&gt;
&nbsp;
// パスワードフィールド
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> input_password_tag<span class="br0">&#40;</span><span class="st_h">'name'</span><span class="sy0">,</span> <span class="st_h">'value'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
 =&gt; &lt;input type=&quot;password&quot; name=&quot;name&quot; id=&quot;name&quot; value=&quot;value&quot; /&gt;
&nbsp;
// 隠しフィールド
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> input_hidden_tag<span class="br0">&#40;</span><span class="st_h">'name'</span><span class="sy0">,</span> <span class="st_h">'value'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
 =&gt; &lt;input type=&quot;hidden&quot; name=&quot;name&quot; id=&quot;name&quot; value=&quot;value&quot; /&gt;
&nbsp;
// 投稿ボタン (テキストとして)
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> submit_tag<span class="br0">&#40;</span><span class="st_h">'Save'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
 =&gt; &lt;input type=&quot;submit&quot; name=&quot;submit&quot; value=&quot;Save&quot; /&gt;
&nbsp;
// 投稿ボタン (画像として)
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> submit_image_tag<span class="br0">&#40;</span><span class="st_h">'submit_img'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
 =&gt; &lt;input type=&quot;image&quot; name=&quot;submit&quot; src=&quot;/images/submit_img.png&quot; /&gt;</pre>

<p><code>submit_image_tag()</code>ヘルパーは同じ構文を使い<code>image_tag()</code>と同じ利点を持ちます。</p>

<blockquote class="note"><p>
  ラジオボタンに関して、デフォルトでは<code>id</code>属性は<code>name</code>属性の値ではなく名前と値の組み合わせに設定されます。自動化された"別のものを選択したときに以前の選択を解除する"機能を手に入れるために同じ名前を持ついくつかのラジオボタンのタグを用意する必要があるからで、<code>id=name</code>の慣習によればページのなかで<code>id</code>属性を持つHTMLタグが存在することを意味します。これは厳密には禁止されています。</p>
</blockquote>

<p>-</p>

<blockquote class="sidebar"><p class="title">
  <strong>フォーム投稿の扱いかた</strong></p>
  
  <p>フォームを通してユーザーによって投稿されたデータをどのように読みとりますか？リクエストパラメーターで利用できるので、アクションは値を得るために<code>$request-&gt;getParameter($elementName)</code>を呼び出すことが必要なだけです。</p>
  
  <p>フォームを表示して処理するためのよい習慣は同じアクションを使うことです。リクエストメソッド(GETもしくはPOST)に従い、フォームのテンプレートが呼び出されるもしくはフォームが処理されるとリクエストは別のアクションにリダイレクトされます。</p>

<pre class="php"><span class="co1">// mymodule/actions/actions.class.phpにおいて</span>
<span class="kw2">public</span> <span class="kw2">function</span> executeEditAuthor<span class="br0">&#40;</span><span class="re0">$request</span><span class="br0">&#41;</span>
<span class="br0">&#123;</span>
  <span class="kw1">if</span> <span class="br0">&#40;</span><span class="sy0">!</span><span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">getRequest</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me1">isMethod</span><span class="br0">&#40;</span><span class="st_h">'post'</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
  <span class="br0">&#123;</span>
    <span class="co1">// フォームを表示する</span>
    <span class="kw1">return</span> sfView<span class="sy0">::</span><span class="me2">SUCCESS</span><span class="sy0">;</span>
  <span class="br0">&#125;</span>
  <span class="kw1">else</span>
  <span class="br0">&#123;</span>
    <span class="co1">// フォーム投稿を扱う</span>
    <span class="re0">$name</span> <span class="sy0">=</span> <span class="re0">$request</span><span class="sy0">-&gt;</span><span class="me1">getParameter</span><span class="br0">&#40;</span><span class="st_h">'name'</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="sy0">...</span>
    <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">redirect</span><span class="br0">&#40;</span><span class="st_h">'mymodule/anotheraction'</span><span class="br0">&#41;</span><span class="sy0">;</span>
  <span class="br0">&#125;</span>
<span class="br0">&#125;</span></pre>
  
  <p>これを機能させるには、フォームのターゲットは表示するアクションと同じアクションでなければなりません。</p>

<pre class="php">// mymodule/templates/editAuthorSuccess.phpにおいて
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> form_tag<span class="br0">&#40;</span><span class="st_h">'mymodule/editAuthor'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
&nbsp;
...</pre>
</blockquote>

<p>symfonyは裏で非同期通信リクエストを行うために専用のフォームヘルパーを提供します。つぎの章では、Ajaxについて焦点を当てて、詳細な説明を行います。</p>

<a name="date.input.widgets" id="date.input.widgets"></a><h3>日付入力ウィジェット</h3>

<p>フォームは日付を読みとるためによく使われます。誤った書式の日付はフォーム投稿が失敗する主な原因です。図10-1で示されるように、<code>rich</code>オプションを<code>true</code>にセットする場合、<code>input_date_tag()</code>ヘルパーはインタラクティブなJavaScriptカレンダーのなかで入力するユーザーを助けます。</p>

<p>図10-1 - リッチな日付入力タグ</p>

<p><img src="images/F1001.png" alt="リッチな日付入力タグ" title="リッチな日付入力タグ" /></p>

<p><code>rich</code>オプションが省略された場合、月、日にち、年の範囲で投入されたヘルパーは3つの<code>&lt;select&gt;</code>タグを出力します。これらのヘルパー(<code>select_day_tag()</code>、<code>select_month_tag()</code>と<code>select_year_tag()</code>)を呼び出すことでこれらのドロップダウンを個別に表示できます。これらの要素のデフォルト値は現在の日にち、月、年です。リスト10-3は日付入力ヘルパーを示してます。</p>

<p>リスト10-3 - 日付入力ヘルパー</p>

<pre class="php"><span class="kw2">&lt;?php</span> <span class="kw1">echo</span> input_date_tag<span class="br0">&#40;</span><span class="st_h">'dateofbirth'</span><span class="sy0">,</span> <span class="st_h">'2005-05-03'</span><span class="sy0">,</span> <span class="st_h">'rich=true'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
 =&gt; a text input tag together with a calendar widget
&nbsp;
// つぎのヘルパーはDateFormヘルパーグループを必要とする
<span class="kw2">&lt;?php</span> use_helper<span class="br0">&#40;</span><span class="st_h">'DateForm'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
&nbsp;
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> select_day_tag<span class="br0">&#40;</span><span class="st_h">'day'</span><span class="sy0">,</span> <span class="nu0">1</span><span class="sy0">,</span> <span class="st_h">'include_custom=日にちを選択する'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
=&gt; &lt;select name=&quot;day&quot; id=&quot;day&quot;&gt;
      &lt;option value=&quot;&quot;&gt;日にちを選択する&lt;/option&gt;
      &lt;option value=&quot;1&quot; selected=&quot;selected&quot;&gt;01&lt;/option&gt;
      &lt;option value=&quot;2&quot;&gt;02&lt;/option&gt;
      ...
      &lt;option value=&quot;31&quot;&gt;31&lt;/option&gt;
    &lt;/select&gt;
&nbsp;
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> select_month_tag<span class="br0">&#40;</span><span class="st_h">'month'</span><span class="sy0">,</span> <span class="nu0">1</span><span class="sy0">,</span> <span class="st_h">'include_custom=月を選択する use_short_month=true'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
=&gt; &lt;select name=&quot;month&quot; id=&quot;month&quot;&gt;
      &lt;option value=&quot;&quot;&gt;月を選択する&lt;/option&gt;
      &lt;option value=&quot;1&quot; selected=&quot;selected&quot;&gt;Jan&lt;/option&gt;
      &lt;option value=&quot;2&quot;&gt;Feb&lt;/option&gt;
      ...
      &lt;option value=&quot;12&quot;&gt;Dec&lt;/option&gt;
    &lt;/select&gt;
&nbsp;
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> select_year_tag<span class="br0">&#40;</span><span class="st_h">'year'</span><span class="sy0">,</span> <span class="nu0">2007</span><span class="sy0">,</span> <span class="st_h">'include_custom=年を選択する year_end=2010'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
 =&gt; &lt;select name=&quot;year&quot; id=&quot;year&quot;&gt;
      &lt;option value=&quot;&quot;&gt;年を選択する&lt;/option&gt;
      &lt;option value=&quot;2006&quot;&gt;2006&lt;/option&gt;
      &lt;option value=&quot;2007&quot; selected=&quot;selected&quot;&gt;2007&lt;/option&gt;
      ...
    &lt;/select&gt;</pre>

<p><code>input_date_tag()</code>ヘルパーが受け入れる日付の値はPHPの<code>strtotime()</code>関数によって認識されるものです。リスト10-4は利用できる書式を示し、リスト10-5は避けなければならない書式を示しています。</p>

<p>リスト10-4 - 日付ヘルパーで受け入れられる日付書式</p>

<pre class="php">// 立派に動作する
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> input_date_tag<span class="br0">&#40;</span><span class="st_h">'test'</span><span class="sy0">,</span> <span class="st_h">'2006-04-01'</span><span class="sy0">,</span> <span class="st_h">'rich=true'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> input_date_tag<span class="br0">&#40;</span><span class="st_h">'test'</span><span class="sy0">,</span> <span class="nu0">1143884373</span><span class="sy0">,</span> <span class="st_h">'rich=true'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> input_date_tag<span class="br0">&#40;</span><span class="st_h">'test'</span><span class="sy0">,</span> <span class="st_h">'now'</span><span class="sy0">,</span> <span class="st_h">'rich=true'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> input_date_tag<span class="br0">&#40;</span><span class="st_h">'test'</span><span class="sy0">,</span> <span class="st_h">'23 October 2005'</span><span class="sy0">,</span> <span class="st_h">'rich=true'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> input_date_tag<span class="br0">&#40;</span><span class="st_h">'test'</span><span class="sy0">,</span> <span class="st_h">'next tuesday'</span><span class="sy0">,</span> <span class="st_h">'rich=true'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> input_date_tag<span class="br0">&#40;</span><span class="st_h">'test'</span><span class="sy0">,</span> <span class="st_h">'1 week 2 days 4 hours 2 seconds'</span><span class="sy0">,</span> <span class="st_h">'rich=true'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
&nbsp;
// nullを返す
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> input_date_tag<span class="br0">&#40;</span><span class="st_h">'test'</span><span class="sy0">,</span> <span class="kw4">null</span><span class="sy0">,</span> <span class="st_h">'rich=true'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> input_date_tag<span class="br0">&#40;</span><span class="st_h">'test'</span><span class="sy0">,</span> <span class="st_h">''</span><span class="sy0">,</span> <span class="st_h">'rich=true'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span></pre>

<p>リスト10-5 - 日付ヘルパーで無効な日付書式</p>

<pre class="php">// 日付 zero = 01/01/1970
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> input_date_tag<span class="br0">&#40;</span><span class="st_h">'test'</span><span class="sy0">,</span> <span class="nu0">0</span><span class="sy0">,</span> <span class="st_h">'rich=true'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
&nbsp;
// 英語ではない日付書式は機能しない
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> input_date_tag<span class="br0">&#40;</span><span class="st_h">'test'</span><span class="sy0">,</span> <span class="st_h">'01/04/2006'</span><span class="sy0">,</span> <span class="st_h">'rich=true'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span></pre>

<a name="rich.text.editing" id="rich.text.editing"></a><h3>リッチなテキスト編集機能</h3>

<p>TinyMCEとFCKEditorウィジェットの統合機能のおかげで、<code>&lt;textarea&gt;</code>タグでもリッチなテキスト編集機能を利用できます。図10-2で示されるように、これらはテキストを太文字、イタリック体、そのほかのスタイルとして整形するためのボタンつきのワードプロセッサのようなインターフェイスを提供します。</p>

<p>図10-2 - リッチなテキスト編集機能</p>

<p><img src="images/F1002.png" alt="リッチなテキスト編集機能" title="リッチなテキスト編集機能" /></p>

<p>両方のウィジェットとも手動でインストールする作業が必要です。2つのウィジェットのインストールの手続きは同じなので、ここではTinyMCEのリッチなテキスト編集機能だけを説明します。プロジェクトのWebサイト(<a href="http://tinymce.moxiecode.com/">http://tinymce.moxiecode.com/</a>)からエディタをダウンロードし、一時フォルダーで解凍する必要があります。リスト10-6で示されるように、<code>tinymce/jscripts/tiny_mce/</code>ディレクトリをプロジェクトの<code>web/js/</code>ディレクトリにコピーし、<code>settings.yml</code>のなかでライブラリへのパスを定義します。</p>

<p>リスト10-6 - TinyMCEライブラリのパスをセットアップする</p>

<pre><code>all:
  .settings:
    rich_text_js_dir:  js/tiny_mce
</code></pre>

<p>セットアップが終了したら、テキストエリアのリッチなテキスト編集機能を利用できるように<code>rich=true</code>オプションを追加して切り替えます。JavaScriptエディタに<code>tinymce_options</code>オプションを渡すことでカスタムオプションを指定することもできます。リスト10-7を示してください。</p>

<p>リスト10-7 - リッチなテキストエリア</p>

<pre class="php"><span class="kw2">&lt;?php</span> <span class="kw1">echo</span> textarea_tag<span class="br0">&#40;</span><span class="st_h">'name'</span><span class="sy0">,</span> <span class="st_h">'default content'</span><span class="sy0">,</span> <span class="st_h">'rich=true size=10x20'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
 =&gt; a rich text edit zone powered by TinyMCE
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> textarea_tag<span class="br0">&#40;</span><span class="st_h">'name'</span><span class="sy0">,</span> <span class="st_h">'default content'</span><span class="sy0">,</span> <span class="st_h">'rich=true size=10x20 tinymce_options=language:&quot;fr&quot;,theme_advanced_buttons2:&quot;separator&quot;'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
=&gt; a rich text edit zone powered by TinyMCE with custom parameters</pre>

<a name="country.language.and.currency.selection" id="country.language.and.currency.selection"></a><h3>国、言語と通貨の選択</h3>

<p>国の選択フィールドを表示する必要がある場合を考えます。しかし国の名前はすべての言語とは同じではないので国のドロップダウンリストのオプションはユーザーのcultureにしたがって変わります(cultureに関する詳細な情報は13章を参照)。リスト10-8で示されるように、<code>select_country_tag()</code>ヘルパーがあなたの代わりにすべてを行います: これは国の名前を国際化し、ISOの標準国コードを値として使います。</p>

<p>リスト10-8 - 国のタグヘルパーを選ぶ</p>

<pre class="php"><span class="kw2">&lt;?php</span> <span class="kw1">echo</span> select_country_tag<span class="br0">&#40;</span><span class="st_h">'country'</span><span class="sy0">,</span> <span class="st_h">'AL'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
 =&gt; &lt;select name=&quot;country&quot; id=&quot;country&quot;&gt;
      &lt;option value=&quot;AF&quot;&gt;アフガニスタン&lt;/option&gt;
      &lt;option value=&quot;AL&quot; selected=&quot;selected&quot;&gt;アルバニア&lt;/option&gt;
      &lt;option value=&quot;DZ&quot;&gt;アルジェリア&lt;/option&gt;
      &lt;option value=&quot;AS&quot;&gt;アメリカ領サモア&lt;/option&gt;
  ...</pre>

<p><code>select_country_tag()</code>ヘルパーと同じように、<code>selext_language_tag()</code>ヘルパーはリスト10-9で示されるような言語のリストを表示します。</p>

<p>リスト10-9 - 言語のタグヘルパーを選ぶ</p>

<pre class="php"><span class="kw2">&lt;?php</span> <span class="kw1">echo</span> select_language_tag<span class="br0">&#40;</span><span class="st_h">'language'</span><span class="sy0">,</span> <span class="st_h">'en'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
 =&gt; &lt;select name=&quot;language&quot; id=&quot;language&quot;&gt;
      ...
      &lt;option value=&quot;elx&quot;&gt;エラム語&lt;/option&gt;
      &lt;option value=&quot;en&quot; selected=&quot;selected&quot;&gt;英語&lt;/option&gt;
      &lt;option value=&quot;enm&quot;&gt;中英語(1100-1500)&lt;/option&gt;
      &lt;option value=&quot;ang&quot;&gt;古英語(ca.450-1100)&lt;/option&gt;
      &lt;option value=&quot;myv&quot;&gt;エルジャ語&lt;/option&gt;
      &lt;option value=&quot;eo&quot;&gt;エスペラント語&lt;/option&gt;
      ...</pre>

<p>3番目のヘルパーは<code>select_currency_tag()</code>ヘルパーで、リスト10-10のような、通貨の一覧を表示します。</p>

<p>リスト10-10 - 通貨タグヘルパーを選ぶ</p>

<pre class="php"><span class="kw2">&lt;?php</span> <span class="kw1">echo</span> select_currency_tag<span class="br0">&#40;</span><span class="st_h">'currency'</span><span class="sy0">,</span> <span class="st_h">'EUR'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
 =&gt; &lt;select name=&quot;currency&quot; id=&quot;currency&quot;&gt;
      ...
      &lt;option value=&quot;ETB&quot;&gt;エチオピアビル&lt;/option&gt;
      &lt;option value=&quot;ETD&quot;&gt;エチオピアドル&lt;/option&gt;
      &lt;option value=&quot;EUR&quot; selected=&quot;selected&quot;&gt;ユーロ&lt;/option&gt;
      &lt;option value=&quot;XBA&quot;&gt;欧州複合単位(EURCO)&lt;/option&gt;
      &lt;option value=&quot;XEU&quot;&gt;欧州通貨単位&lt;/option&gt;
      ...</pre>

<blockquote class="note"><p>
  3つのすべてのヘルパーはオプションの配列である3番目の引数を受けとります。これは表示されるオプションを特定のセット: <code>array('countries' =&gt; array ('FR', 'DE'))</code>のように制限できます。<code>select_language_tag()</code>に対するオプションの名前は<code>languages</code>で<code>select_currency_tag()</code>に対するオプションの名前は<code>currencies</code>です。
  たいていの場合、セットを既知でサポートされる値のリスト、とりわけ期限切れの項目を含む可能性があるリスト、に制限することに意味があります。</p>
  
  <p><code>select_currency_tag()</code>はオプションに表示されるものに影響を与える<code>display</code>という名前の追加オプションを提供します。これは<code>symbol</code>、<code>code</code>もしくは<code>name</code>の1つに設定できます。</p>
</blockquote>

<a name="form.helpers.for.objects" id="form.helpers.for.objects"></a><h2>オブジェクトのためのフォームヘルパー</h2>

<p>フォームの要素がオブジェクトのプロパティを編集するために使われるとき、標準のリンクヘルパーを書く作業が退屈になることがあります。たとえば、<code>Customer</code>オブジェクトの<code>telephone</code>属性を編集するには、つぎのように書くことになります:</p>

<pre class="php"><span class="kw2">&lt;?php</span> <span class="kw1">echo</span> input_tag<span class="br0">&#40;</span><span class="st_h">'telephone'</span><span class="sy0">,</span> <span class="re0">$customer</span><span class="sy0">-&gt;</span><span class="me1">getTelephone</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
=&gt; &lt;input type=&quot;text&quot; name=&quot;telephone&quot; id=&quot;telephone&quot; value=&quot;0123456789&quot; /&gt;</pre>

<p>属性の名前を繰り返すことを避けるために、symfonyはそれぞれのフォームヘルパーに対して代わりのオブジェクトフォームヘルパーを提供します。オブジェクトフォームヘルパーはオブジェクトとメソッドの名前からフォーム要素の名前とデフォルト値を推測します。以前の<code>input_tag()</code>はつぎのコードと同等です:</p>

<pre class="php"><span class="kw2">&lt;?php</span> <span class="kw1">echo</span> object_input_tag<span class="br0">&#40;</span><span class="re0">$customer</span><span class="sy0">,</span> <span class="st_h">'getTelephone'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
=&gt; &lt;input type=&quot;text&quot; name=&quot;telephone&quot; id=&quot;telephone&quot; value=&quot;0123456789&quot; /&gt;</pre>

<p><code>object_input_tag()</code>に関して簡潔さは重要ではないかもしれません。しかしながら、すべての標準のフォームヘルパーは対応するオブジェクトフォームヘルパーを持ち、これらはすべて同じ構文を共有します。これはフォームの生成作業をとても楽にします。scaffoldingと生成されたadministration(14章を参照)でオブジェクトフォームヘルパーが広範囲に使われる理由はそういうわけです。リスト10-11はヘルパーからのオブジェクトのリストです。</p>

<p>リスト10-11 - オブジェクトフォームヘルパーの構文</p>

<pre class="php"><span class="kw2">&lt;?php</span> <span class="kw1">echo</span> object_input_tag<span class="br0">&#40;</span><span class="re0">$object</span><span class="sy0">,</span> <span class="re0">$method</span><span class="sy0">,</span> <span class="re0">$options</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> object_input_date_tag<span class="br0">&#40;</span><span class="re0">$object</span><span class="sy0">,</span> <span class="re0">$method</span><span class="sy0">,</span> <span class="re0">$options</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> object_input_hidden_tag<span class="br0">&#40;</span><span class="re0">$object</span><span class="sy0">,</span> <span class="re0">$method</span><span class="sy0">,</span> <span class="re0">$options</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> object_textarea_tag<span class="br0">&#40;</span><span class="re0">$object</span><span class="sy0">,</span> <span class="re0">$method</span><span class="sy0">,</span> <span class="re0">$options</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> object_checkbox_tag<span class="br0">&#40;</span><span class="re0">$object</span><span class="sy0">,</span> <span class="re0">$method</span><span class="sy0">,</span> <span class="re0">$options</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> object_select_tag<span class="br0">&#40;</span><span class="re0">$object</span><span class="sy0">,</span> <span class="re0">$method</span><span class="sy0">,</span> <span class="re0">$options</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> object_select_country_tag<span class="br0">&#40;</span><span class="re0">$object</span><span class="sy0">,</span> <span class="re0">$method</span><span class="sy0">,</span> <span class="re0">$options</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> object_select_language_tag<span class="br0">&#40;</span><span class="re0">$object</span><span class="sy0">,</span> <span class="re0">$method</span><span class="sy0">,</span> <span class="re0">$options</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span></pre>

<p><code>object_password_tag()</code>ヘルパーは存在しません。以前ユーザーが入力した値をもとに、デフォルト値をパスワードのタグに渡すことはよくない習慣だからです。</p>

<blockquote class="caution"><p>
  通常のフォームヘルパーとは異なり、<code>use_helper('Object')</code>を持つテンプレート内で<code>Object</code>ヘルパーグループの使用を明示的に宣言した場合のみオブジェクトフォームヘルパーは利用できます。</p>
</blockquote>

<p>すべてのオブジェクトフォームヘルパーのなかでもっとも面白いのはドロップダウンリストに関連する<code>objects_for_select()</code>と<code>object_select_tag()</code>です。</p>

<a name="populating.dropdown.lists.with.objects" id="populating.dropdown.lists.with.objects"></a><h3>ドロップダウンをオブジェクトで投入する</h3>

<p><code>options_for_select()</code>ヘルパーは、ほかの標準ヘルパーで以前説明されたものですが、リスト10-12で示されるように、PHPの連想配列をオプションのリストに変換します。</p>

<p>リスト10-12 - <code>options_for_select()</code>を利用して配列に基づくオプションのリストを作成する</p>

<pre class="php"><span class="kw2">&lt;?php</span> <span class="kw1">echo</span> options_for_select<span class="br0">&#40;</span><span class="kw3">array</span><span class="br0">&#40;</span>
  <span class="st_h">'1'</span> <span class="sy0">=&gt;</span> <span class="st_h">'Steve'</span><span class="sy0">,</span>
  <span class="st_h">'2'</span> <span class="sy0">=&gt;</span> <span class="st_h">'Bob'</span><span class="sy0">,</span>
  <span class="st_h">'3'</span> <span class="sy0">=&gt;</span> <span class="st_h">'Albert'</span><span class="sy0">,</span>
  <span class="st_h">'4'</span> <span class="sy0">=&gt;</span> <span class="st_h">'Ian'</span><span class="sy0">,</span>
  <span class="st_h">'5'</span> <span class="sy0">=&gt;</span> <span class="st_h">'Buck'</span>
<span class="br0">&#41;</span><span class="sy0">,</span> <span class="nu0">4</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
 =&gt; &lt;option value=&quot;1&quot;&gt;Steve&lt;/option&gt;
    &lt;option value=&quot;2&quot;&gt;Bob&lt;/option&gt;
    &lt;option value=&quot;3&quot;&gt;Albert&lt;/option&gt;
    &lt;option value=&quot;4&quot; selected=&quot;selected&quot;&gt;Ian&lt;/option&gt;
    &lt;option value=&quot;5&quot;&gt;Buck&lt;/option&gt;</pre>

<p>すでに、<code>Propel</code>のクエリの結果から得られた、<code>Author</code>クラスのオブジェクトの配列が存在することを前提とします。この配列をもとにオプションのリストを作りたい場合、リスト10-13で示されるように、それぞれのオブジェクトの<code>id</code>と<code>name</code>を読みとるためにループする必要があります。</p>

<p>リスト10-13 - <code>options_for_select()</code>を使ってオブジェクト配列をもとにオプションのリストを作る</p>

<pre class="php">// アクションのなか
$options = array();
foreach ($authors as $author)
{
  $options[$author-&gt;getId()] = $author-&gt;getName();
}
$this-&gt;options = $options;
&nbsp;
// テンプレートのなか
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> options_for_select<span class="br0">&#40;</span><span class="re0">$options</span><span class="sy0">,</span> <span class="nu0">4</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span></pre>

<p>この種の処理作業はよく行われるので、symfonyはこの作業を自動化するヘルパーを用意します: <code>objects_for_select()</code>はオブジェクトの配列から直接オプションリストを作ります。ヘルパーは2つの追加パラメーターが必要です: <code>value</code>を読みとるために使われるメソッド名と生成される<code>&lt;option&gt;</code>タグのテキスト内容です。リスト10-13はつぎのシンプルなフォームと同等です:</p>

<pre class="php"><span class="kw2">&lt;?php</span> <span class="kw1">echo</span> objects_for_select<span class="br0">&#40;</span><span class="re0">$authors</span><span class="sy0">,</span> <span class="st_h">'getId'</span><span class="sy0">,</span> <span class="st_h">'getName'</span><span class="sy0">,</span> <span class="nu0">4</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span></pre>

<p>これはスマートで速く書けますが、外部キーのカラムを処理するとき、symfonyはさらに掘り下げます。</p>

<a name="creating.a.dropdown.list.based.on.a.foreign.key.column" id="creating.a.dropdown.list.based.on.a.foreign.key.column"></a><h3>外部キーのカラムをもとにドロップダウンリストを作る</h3>

<p>外部キーのカラムが取得できる値は外部テーブルのレコードの主キーの値です。たとえば、<code>article</code>テーブルが<code>author</code>テーブルへの外部キーである<code>author_id</code>カラムを持つ場合、このカラムで利用可能な値は<code>author</code>テーブルのすべてのレコードの<code>id</code>です。基本的には、記事の作者を編集するドロップダウンリストはリスト10-14のようになります。</p>

<p>リスト10-14 - <code>objects_for_select()</code>を使って外部キーをもとにオプションのリストを作る</p>

<pre class="php"><span class="kw2">&lt;?php</span> <span class="kw1">echo</span> select_tag<span class="br0">&#40;</span><span class="st_h">'author_id'</span><span class="sy0">,</span> objects_for_select<span class="br0">&#40;</span>
  AuthorPeer<span class="sy0">::</span><span class="me2">doSelect</span><span class="br0">&#40;</span><span class="kw2">new</span> Criteria<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">,</span>
  <span class="st_h">'getId'</span><span class="sy0">,</span>
  <span class="st_h">'__toString'</span><span class="sy0">,</span>
  <span class="re0">$article</span><span class="sy0">-&gt;</span><span class="me1">getAuthorId</span><span class="br0">&#40;</span><span class="br0">&#41;</span>
<span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
=&gt; &lt;select name=&quot;author_id&quot; id=&quot;author_id&quot;&gt;
      &lt;option value=&quot;1&quot;&gt;Steve&lt;/option&gt;
      &lt;option value=&quot;2&quot;&gt;Bob&lt;/option&gt;
      &lt;option value=&quot;3&quot;&gt;Albert&lt;/option&gt;
      &lt;option value=&quot;4&quot; selected=&quot;selected&quot;&gt;Ian&lt;/option&gt;
      &lt;option value=&quot;5&quot;&gt;Buck&lt;/option&gt;
    &lt;/select&gt;</pre>

<p><code>object_select_tag()</code>は単独ですべてを行います。これは外部テーブルの可能なレコードの名前で投入されたドロップダウンリストを表示します。ヘルパーはスキーマから外部テーブルと外部カラムを推測できるので、構文はとても簡潔です。リスト10-13はつぎのコードと同等です:</p>

<pre class="php"><span class="kw2">&lt;?php</span> <span class="kw1">echo</span> object_select_tag<span class="br0">&#40;</span><span class="re0">$article</span><span class="sy0">,</span> <span class="st_h">'getAuthorId'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span></pre>

<p><code>object_select_tag()</code>ヘルパーはパラメーターとして渡されるメソッドの名前をもとに関連するピアクラスの名前(この例では<code>AuthorPeer</code>)を推測します。しかしながら、<code>related_class</code>オプションを3番目の引数に設定することで独自のクラスを指定できます。<code>&lt;option&gt;</code>タグのテキスト内容はレコード名で、オブジェクトクラスの<code>__toString()</code>メソッドの結果です(<code>$author-&gt;__toString()</code>メソッドが未定義の場合、主キーが代わりに使われます)。加えて、オプションのリストは空の基準値を持つ<code>doSelect()</code>メソッドで構成されます; これは作成日順に並べられたすべてのレコードを返します。特定の順番でレコードの部分集合だけを表示したい場合、この選択をオブジェクトの配列として返すピアクラスのなかでメソッドを作り、これを<code>peer_method</code>オプションに設定します。最後に、<code>include_blank</code>と<code>include_custom</code>オプションを設定することでドロップダウンリストのトップに、空白のオプションもしくはカスタムオプションを追加できます。リスト10-15は<code>object_select_tag()</code>ヘルパーに対するこれらの異なるオプションを示しています。</p>

<p>リスト10-15 - <code>object_select_tag()</code>ヘルパーのオプション</p>

<pre class="php">// 基本構文
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> object_select_tag<span class="br0">&#40;</span><span class="re0">$article</span><span class="sy0">,</span> <span class="st_h">'getAuthorId'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
// AuthorPeer::doSelect(new Criteria())からリストを作る
&nbsp;
// 可能な値を読みとるために使われるピアクラスを変更する
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> object_select_tag<span class="br0">&#40;</span><span class="re0">$article</span><span class="sy0">,</span> <span class="st_h">'getAuthorId'</span><span class="sy0">,</span> <span class="st_h">'related_class=Foobar'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
// FoobarPeer::doSelect(new Criteria())からリストを作る
&nbsp;
// 可能な値を読みとるためにピアクラスを変更する
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> object_select_tag<span class="br0">&#40;</span><span class="re0">$article</span><span class="sy0">,</span> <span class="st_h">'getAuthorId'</span><span class="sy0">,</span><span class="st_h">'peer_method=getMostFamousAuthors'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
// AuthorPeer::getMostFamousAuthors(new Criteria())からリストを作る
&nbsp;
// リストのトップで&lt;option value=&quot;&quot;&gt;&amp;nbsp;&lt;/option&gt;を追加する
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> object_select_tag<span class="br0">&#40;</span><span class="re0">$article</span><span class="sy0">,</span> <span class="st_h">'getAuthorId'</span><span class="sy0">,</span> <span class="st_h">'include_blank=true'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
&nbsp;
// リストのトップで&lt;option value=&quot;&quot;&gt;Choose an author&lt;/option&gt;を追加する
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> object_select_tag<span class="br0">&#40;</span><span class="re0">$article</span><span class="sy0">,</span> <span class="st_h">'getAuthorId'</span><span class="sy0">,</span>
  <span class="st_h">'include_custom=Choose an author'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span></pre>

<a name="updating.objects" id="updating.objects"></a><h3>オブジェクトを更新する</h3>

<p>オブジェクトヘルパーを利用してオブジェクトのプロパティを編集するための専用フォームはアクションのなかで扱うよりも簡単です。たとえば、<code>name</code>、<code>age</code>、<code>address</code>属性を持つ<code>Author</code>クラスのオブジェクトがある場合、フォームはリスト10-16のように書きます。</p>

<p>リスト10-16 - オブジェクトヘルパーだけを持つフォーム</p>

<pre class="php"><span class="kw2">&lt;?php</span> <span class="kw1">echo</span> form_tag<span class="br0">&#40;</span><span class="st_h">'author/update'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
  <span class="kw2">&lt;?php</span> <span class="kw1">echo</span> object_input_hidden_tag<span class="br0">&#40;</span><span class="re0">$author</span><span class="sy0">,</span> <span class="st_h">'getId'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
  名前: <span class="kw2">&lt;?php</span> <span class="kw1">echo</span> object_input_tag<span class="br0">&#40;</span><span class="re0">$author</span><span class="sy0">,</span> <span class="st_h">'getName'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>&lt;br /&gt;
  年齢:  <span class="kw2">&lt;?php</span> <span class="kw1">echo</span> object_input_tag<span class="br0">&#40;</span><span class="re0">$author</span><span class="sy0">,</span> <span class="st_h">'getAge'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>&lt;br /&gt;
  アドレス: &lt;br /&gt;
         <span class="kw2">&lt;?php</span> <span class="kw1">echo</span> object_textarea_tag<span class="br0">&#40;</span><span class="re0">$author</span><span class="sy0">,</span> <span class="st_h">'getAddress'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
&lt;/form&gt;</pre>

<p>リスト10-17で示されるように、フォームが投稿されたときに、呼び出される<code>author</code>モジュールの<code>update</code>アクションはPropelによって生成された<code>fromArray()</code>メソッドによって簡単にオブジェクトを更新できます。</p>

<p>リスト10-17 - オブジェクトフォームヘルパーに基づくフォーム投稿を扱う</p>

<pre class="php"><span class="kw2">public</span> <span class="kw2">function</span> executeUpdate<span class="br0">&#40;</span><span class="re0">$request</span><span class="br0">&#41;</span>
<span class="br0">&#123;</span>
  <span class="re0">$author</span> <span class="sy0">=</span> AuthorPeer<span class="sy0">::</span><span class="me2">retrieveByPk</span><span class="br0">&#40;</span><span class="re0">$request</span><span class="sy0">-&gt;</span><span class="me1">getParameter</span><span class="br0">&#40;</span><span class="st_h">'id'</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span>
  <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">forward404Unless</span><span class="br0">&#40;</span><span class="re0">$author</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
  <span class="re0">$author</span><span class="sy0">-&gt;</span><span class="me1">fromArray</span><span class="br0">&#40;</span><span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">getRequest</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me1">getParameterHolder</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me1">getAll</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">,</span>BasePeer<span class="sy0">::</span><span class="me2">TYPE_FIELDNAME</span><span class="br0">&#41;</span><span class="sy0">;</span>
  <span class="re0">$author</span><span class="sy0">-&gt;</span><span class="me1">save</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
  <span class="kw1">return</span> <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">redirect</span><span class="br0">&#40;</span><span class="st_h">'/author/show?id='</span><span class="sy0">.</span><span class="re0">$author</span><span class="sy0">-&gt;</span><span class="me1">getId</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span>
<span class="br0">&#125;</span></pre>

<a name="form.validation" id="form.validation"></a><h2>フォームのバリデーション</h2>

<blockquote class="note"><p>
  このセクションで説明されている機能はsymfony 1.1で廃止され<code>sfCompat10</code>プラグインを有効にした場合のみに動作します。</p>
</blockquote>

<p>6章ではリクエストパラメーターをバリデートするためにアクションクラスで<code>validateXXX()</code>メソッドを使う方法を説明しました。しかしながら、フォーム投稿をバリデートするこのテクニックを利用する場合、同じコードの一部を何度も書き直すことになります。symfonyはアクションクラスのなかのPHPコードの代わりに、YAMLファイルだけに依存する、フォームのバリデーションの代替テクニックを提供します。</p>

<p>フォームのバリデーション機能を実証するために、最初にリスト10-18で示されているサンプルのフォームを考えてみましょう。<code>name</code>、<code>email</code>、<code>age</code>、と<code>message</code>フィールドを持つ、古典的な問い合わせフォームです。</p>

<p>リスト10-18 - 問い合わせフォームのサンプル(<code>modules/contact/templates/indexSuccess.php</code>)</p>

<pre class="php"><span class="kw2">&lt;?php</span> <span class="kw1">echo</span> form_tag<span class="br0">&#40;</span><span class="st_h">'contact/send'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
  名前:    <span class="kw2">&lt;?php</span> <span class="kw1">echo</span> input_tag<span class="br0">&#40;</span><span class="st_h">'name'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>&lt;br /&gt;
  Eメール:   <span class="kw2">&lt;?php</span> <span class="kw1">echo</span> input_tag<span class="br0">&#40;</span><span class="st_h">'email'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>&lt;br /&gt;
  年齢:     <span class="kw2">&lt;?php</span> <span class="kw1">echo</span> input_tag<span class="br0">&#40;</span><span class="st_h">'age'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>&lt;br /&gt;
  メッセージ: <span class="kw2">&lt;?php</span> <span class="kw1">echo</span> textarea_tag<span class="br0">&#40;</span><span class="st_h">'message'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>&lt;br /&gt;
  <span class="kw2">&lt;?php</span> <span class="kw1">echo</span> submit_tag<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
&lt;/form&gt;</pre>

<p>フォームのバリデーションの原則はユーザーが不正なデータを入力しフォームに投稿した場合、つぎのページでエラーメッセージを表示することです。簡単な英語で、サンプルフォームに対して有効なデータを定義してみましょう:</p>

<ul>
<li><code>name</code>フィールドが必要です。2文字から100文字のテキストエントリーでなければなりません。</li>
<li><code>email</code>フィールドが必要です。2文字から100文字までのテキストエントリーかつ有効なEメールアドレスでなければなりません。</li>
<li><code>age</code>フィールドが必要です。0から120の整数でなければなりません。</li>
<li><code>message</code>フィールドが必要です。</li>
</ul>

<p>問い合わせフォームのためにもっと複雑なバリデーションルールを定義することができますが、バリデーションの可能性を実証するにはこれで十分です。</p>

<blockquote class="note"><p>
  フォームのバリデーションはサーバーサイドかつ/もしくはクライアントサイドで行われます。サーバーサイドのバリデーションは間違ったデータでデータベースが汚染されることを避けるために必須です。クライアントサイドのバリデーションはユーザーエクスペリエンスを大いに高めますが、オプションです。クライアントサイドのバリデーションはカスタムJavaScriptで行われます。</p>
</blockquote>

<a name="validators" id="validators"></a><h3>バリデーター</h3>

<p>上記の例において<code>name</code>フィールドと<code>email</code>フィールドが共通のバリデーションルールを共有していることがわかります。バリデーションルールのいくつかはWebフォームで頻繁に使われるのでsymfonyはこれらのバリデーターを実装するPHPコードにまとめます。バリデーター(validator)は<code>execute()</code>メソッドを提供するシンプルなクラスです。このメソッドはパラメーターとしてフィールドの値を必要とし、値が有効な場合は<code>true</code>を、そうでなければ<code>false</code>を返します。</p>

<p>symfonyはいくつかのバリデーターを搭載しています(この章のあとのほうの"symfonyの標準バリデーター"で説明します)が、今回は<code>sfStringValidator</code>を重点的にとり組んでみましょう。このバリデーターは入力が文字列であり、サイズが2つの指定文字数の間に収まっていることをチェックします(<code>initialize()</code>メソッドを呼び出すときに定義されます)。<code>name</code>フィールドをバリデートするために求められるものがまさにこれです。リスト10-19はバリデーションメソッドでこのバリデーターを使う方法を示しています。</p>

<p>リスト10-19 - 再利用可能なバリデーターでリクエストパラメーターをバリデートする(<code>modules/contact/action/actions.class.php</code>)</p>

<pre class="php"><span class="kw2">public</span> <span class="kw2">function</span> validateSend<span class="br0">&#40;</span><span class="re0">$request</span><span class="br0">&#41;</span>
<span class="br0">&#123;</span>
  <span class="re0">$name</span> <span class="sy0">=</span> <span class="re0">$request</span><span class="sy0">-&gt;</span><span class="me1">getParameter</span><span class="br0">&#40;</span><span class="st_h">'name'</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
  <span class="co1">// nameフィールドが求められる</span>
  <span class="kw1">if</span> <span class="br0">&#40;</span><span class="sy0">!</span><span class="re0">$name</span><span class="br0">&#41;</span>
  <span class="br0">&#123;</span>
    <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">getRequest</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me1">setError</span><span class="br0">&#40;</span><span class="st_h">'name'</span><span class="sy0">,</span> <span class="st_h">'名前のフィールドは空白であってはなりません'</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
    <span class="kw1">return</span> <span class="kw4">false</span><span class="sy0">;</span>
  <span class="br0">&#125;</span>
&nbsp;
  <span class="co1">// nameフィールドは2文字から100文字の間のテキストエントリーでなければならない</span>
  <span class="re0">$myValidator</span> <span class="sy0">=</span> <span class="kw2">new</span> sfStringValidator<span class="br0">&#40;</span><span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">getContext</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">,</span> <span class="kw3">array</span><span class="br0">&#40;</span>
    <span class="st_h">'min'</span>       <span class="sy0">=&gt;</span> <span class="nu0">2</span><span class="sy0">,</span>
    <span class="st_h">'min_error'</span> <span class="sy0">=&gt;</span> <span class="st_h">'この名前は短すぎます(最小は2文字)'</span><span class="sy0">,</span>
    <span class="st_h">'max'</span>       <span class="sy0">=&gt;</span> <span class="nu0">100</span><span class="sy0">,</span>
    <span class="st_h">'max_error'</span> <span class="sy0">=&gt;</span> <span class="st_h">'この名前は長すぎます(最大で100文字)'</span><span class="sy0">,</span>
  <span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span>
  <span class="kw1">if</span> <span class="br0">&#40;</span><span class="sy0">!</span><span class="re0">$myValidator</span><span class="sy0">-&gt;</span><span class="me1">execute</span><span class="br0">&#40;</span><span class="re0">$name</span><span class="sy0">,</span> <span class="re0">$error</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
  <span class="br0">&#123;</span>
    <span class="kw1">return</span> <span class="kw4">false</span><span class="sy0">;</span>
  <span class="br0">&#125;</span>
&nbsp;
  <span class="kw1">return</span> <span class="kw4">true</span><span class="sy0">;</span>
<span class="br0">&#125;</span></pre>

<p>ユーザーがリスト10-18のフォームで<code>name</code>フィールドの<code>a</code>の値を投稿する場合、<code>sfStringValidator</code>の<code>execute()</code>メソッドは<code>false</code>を返します(文字列の最少の長さが2文字だからです)。<code>validateSend()</code>メソッドが失敗し、<code>executeSend()</code>メソッドの代わりに<code>handleErrorSend()</code>メソッドが呼び出されます。</p>

<blockquote class="tip"><p>
  <code>sfRequest</code>オブジェクトの<code>setError()</code>メソッドはテンプレートに情報を渡すので、テンプレートはエラーメッセージを表示できます(この章の後の"エラーメッセージをフォームに表示する"のセクションで説明されます)。バリデーターはエラーを内部で設定するので、異なるバリデーションを行わない場合のために異なるエラーを定義できます。これが<code>sfStringValidator</code>の<code>min_error</code>と<code>max_error</code>初期化パラメーターの目的です。</p>
</blockquote>

<p>上記の例で定義されたすべてのルールはバリデーターに翻訳できます:</p>

<ul>
<li><code>name</code>: <code>sfStringValidator</code> (<code>min=2</code>, <code>max=100</code>)</li>
<li><code>email</code>: <code>sfStringValidator</code> (<code>min=2</code>, <code>max=100</code>)と<code>sfEmailValidator</code></li>
<li><code>age</code>: <code>sfNumberValidator</code> (<code>min=0</code>, <code>max=120</code>)</li>
</ul>

<p>フィールドが求められるという事実はバリデーターによって処理されません。</p>

<a name="validation.file" id="validation.file"></a><h3>バリデーションファイル</h3>

<p><code>validateSend()</code>メソッドのバリデーターで問い合わせフォームのバリデーションを簡単に実装できますが、多くのコードを繰り返すことを意味します。symfonyはフォームのためにバリデーションルールを定義するYAMLを使う代替方法を提供します。たとえば、リスト10-20は<code>name</code>フィールドのバリデーションルールの翻訳を示し、その結果はリスト10-19のものと同等です。</p>

<p>リスト10-20 - バリデーションファイル(<code>modules/contact/validate/send.yml</code>)</p>

<pre><code>fields:
  name:
    required:
      msg:       名前のフィールドは空白であってはなりません
    sfStringValidator:
      min:       2
      min_error: この名前は短すぎます。(最小で2文字)
      max:       100
      max_error: この名前は長すぎます。(最大で100文字)
</code></pre>

<p>バリデーションファイルにおいて、<code>fields</code>ヘッダーは、必要であればバリデートされるフィールド、と値が存在するときにテストされるべきバリデーターの一覧を表示します。それぞれのバリデーターの値はバリデーターを手動で初期化するときに使うものと同じです。フィールドは必要なバリデーターの数だけバリデートできます。</p>

<blockquote class="note"><p>
  バリデーターが失敗するときはバリデーションプロセスは停止しません。symfonyはすべてのバリデーターをテストし、少なくともそれらの1つが失敗した場合にバリデーションが失敗したことを宣言します。バリデーションファイルのルールのいくつかが失敗した場合でも、symfonyはまだ<code>validateXXX()</code>メソッドを探しそれを実行します。2つのバリデーションのテクニックはお互いを補い合っています。利点は複数の失敗をともなうフォームにおいて、すべてのエラーメッセージが表示されることです。</p>
</blockquote>

<p>バリデーションファイルはモジュールの<code>validate/</code>ディレクトリに設置され、これらがバリデートしなければならないアクションの名前を取って名づけられます。たとえばリスト10-19は<code>validate/send.yml</code>という名前のファイルに保存されなければなりません。</p>

<a name="redisplaying.the.form" id="redisplaying.the.form"></a><h3>フォームを再表示する</h3>

<p>デフォルトでは、symfonyはバリデーションの処理が失敗するときはいつもアクションクラスの<code>handleErrorSend()</code>メソッドを探す、もしくはメソッドが存在しない場合は<code>sendError.php</code>テンプレートを表示します。</p>

<p>失敗したバリデーションをユーザーに知らせる通常の方法はエラーメッセージをともなうフォームを再表示することです。この目的のには、リスト10-21で示されるように、<code>handleErrorSend()</code>メソッドをオーバーライドし、フォームを表示するアクション(たとえば、<code>module/index</code>)へのリダイレクトで終わらせる必要があります。</p>

<p>リスト10-21 - フォームを再表示する(<code>modules/contact/actions/actions.class.php</code>)</p>

<pre class="php"><span class="kw2">class</span> ContactActions <span class="kw2">extends</span> sfActions
<span class="br0">&#123;</span>
  <span class="kw2">public</span> <span class="kw2">function</span> executeIndex<span class="br0">&#40;</span><span class="br0">&#41;</span>
  <span class="br0">&#123;</span>
    <span class="co1">//フォームを表示する</span>
  <span class="br0">&#125;</span>
&nbsp;
  <span class="kw2">public</span> <span class="kw2">function</span> handleErrorSend<span class="br0">&#40;</span><span class="br0">&#41;</span>
  <span class="br0">&#123;</span>
    <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">forward</span><span class="br0">&#40;</span><span class="st_h">'contact'</span><span class="sy0">,</span> <span class="st_h">'index'</span><span class="br0">&#41;</span><span class="sy0">;</span>
  <span class="br0">&#125;</span>
&nbsp;
  <span class="kw2">public</span> <span class="kw2">function</span> executeSend<span class="br0">&#40;</span><span class="br0">&#41;</span>
  <span class="br0">&#123;</span>
    <span class="co1">//フォーム投稿を処理する</span>
  <span class="br0">&#125;</span>
<span class="br0">&#125;</span></pre>

<p>フォームを表示してフォーム投稿を処理するために同じアクションを選ぶ場合、リスト10-22で示されるように、<code>handleErrorSend()</code>メソッドは<code>sendSuccess.php</code>からフォームを再表示するために、単に<code>sfView::SUCCESS</code>を返します。</p>

<p>リスト10-22 - フォームを表示して処理する単独のアクション(<code>modules/contact/actions/actions.class.php</code>)</p>

<pre class="php"><span class="kw2">class</span> ContactActions <span class="kw2">extends</span> sfActions
<span class="br0">&#123;</span>
  <span class="kw2">public</span> <span class="kw2">function</span> executeSend<span class="br0">&#40;</span><span class="br0">&#41;</span>
  <span class="br0">&#123;</span>
    <span class="kw1">if</span> <span class="br0">&#40;</span><span class="sy0">!</span><span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">getRequest</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me1">isMethod</span><span class="br0">&#40;</span><span class="st_h">'post'</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
    <span class="br0">&#123;</span>
      <span class="co1">// テンプレートのためのデータを表示する</span>
&nbsp;
      <span class="co1">// フォームを表示する</span>
      <span class="kw1">return</span> sfView<span class="sy0">::</span><span class="me2">SUCCESS</span><span class="sy0">;</span>
    <span class="br0">&#125;</span>
    <span class="kw1">else</span>
    <span class="br0">&#123;</span>
      <span class="co1">// 投稿を処理する</span>
      <span class="sy0">...</span>
      <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">redirect</span><span class="br0">&#40;</span><span class="st_h">'mymodule/anotheraction'</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="br0">&#125;</span>
  <span class="br0">&#125;</span>
  <span class="kw2">public</span> <span class="kw2">function</span> handleErrorSend<span class="br0">&#40;</span><span class="br0">&#41;</span>
  <span class="br0">&#123;</span>
    <span class="co1">// テンプレートに対してデータを表示する</span>
&nbsp;
    <span class="co1">// フォームを表示する</span>
    <span class="kw1">return</span> sfView<span class="sy0">::</span><span class="me2">SUCCESS</span><span class="sy0">;</span>
  <span class="br0">&#125;</span>
<span class="br0">&#125;</span></pre>

<p><code>executeSend()</code>メソッドと<code>handleErrorSend()</code>メソッドのなかで繰り返すことを避けるために、データを用意する必要のあるロジックをアクションクラスのprotectedとして定義されたメソッドにリファクタリングすることができます。</p>

<p>新しい設定によって、ユーザーが無効な名前を入力した場合、フォームは再び表示されますが、入力されたデータは失われ、エラーメッセージは失敗の理由を表示しません。最後の問題を解決するには、誤ったフィールドに近いエラーメッセージを挿入するために、フォームを表示するテンプレートを修正しなければなりません。</p>

<a name="displaying.the.error.messages.in.the.form" id="displaying.the.error.messages.in.the.form"></a><h3>フォームのなかでエラーメッセージを表示する</h3>

<p>バリデーターパラメーターとして定義されたエラーメッセージはフィールドがバリデーションを失敗したときにリクエストに追加されます(リスト10-18で示されるように、<code>setError()</code>メソッドを用いてエラーを手動で追加できる)。<code>sfRequest</code>オブジェクトはエラーメッセージを読みとるために2つの便利なメソッド: <code>hasError()</code>と<code>getError()</code>を提供します。それぞれのメソッドはパラメーターとしてフィールドの名前を必要とします。加えて、1つもしくは多くのフォールドが無効なデータを含むという事実が注目されるように<code>hasErrors()</code>メソッドでアラートをフォームのトップに表示できます。リスト10-23と10-24はこれらのメソッドの使いかたを示しています。</p>

<p>リスト10-23 - フォームのトップでエラーメッセージを表示する(<code>templates/indexSuccess.php</code>)</p>

<pre class="php"><span class="kw2">&lt;?php</span> <span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$sf_request</span><span class="sy0">-&gt;</span><span class="me1">hasErrors</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">:</span> <span class="sy1">?&gt;</span>
  &lt;p&gt;あなたが入力したデータは無効のようです。
  つぎのエラーを修正して再投稿して下さるようお願いします:&lt;/p&gt;
  &lt;ul&gt;
  <span class="kw2">&lt;?php</span> <span class="kw1">foreach</span><span class="br0">&#40;</span><span class="re0">$sf_request</span><span class="sy0">-&gt;</span><span class="me1">getErrors</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="kw1">as</span> <span class="re0">$name</span> <span class="sy0">=&gt;</span> <span class="re0">$error</span><span class="br0">&#41;</span><span class="sy0">:</span> <span class="sy1">?&gt;</span>
    &lt;li&gt;<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> <span class="re0">$name</span> <span class="sy1">?&gt;</span>: <span class="kw2">&lt;?php</span> <span class="kw1">echo</span> <span class="re0">$error</span> <span class="sy1">?&gt;</span>&lt;/li&gt;
  <span class="kw2">&lt;?php</span> <span class="kw1">endforeach</span><span class="sy0">;</span> <span class="sy1">?&gt;</span>
  &lt;/ul&gt;
<span class="kw2">&lt;?php</span> <span class="kw1">endif</span><span class="sy0">;</span> <span class="sy1">?&gt;</span></pre>

<p>リスト10-24 - エラーメッセージをフォーム内部に表示する(<code>templates/indexSuccess.php</code>)</p>

<pre class="php"><span class="kw2">&lt;?php</span> <span class="kw1">echo</span> form_tag<span class="br0">&#40;</span><span class="st_h">'contact/send'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
  <span class="kw2">&lt;?php</span> <span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$sf_request</span><span class="sy0">-&gt;</span><span class="me1">hasError</span><span class="br0">&#40;</span><span class="st_h">'name'</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">:</span> <span class="sy1">?&gt;</span>
    <span class="kw2">&lt;?php</span> <span class="kw1">echo</span> <span class="re0">$sf_request</span><span class="sy0">-&gt;</span><span class="me1">getError</span><span class="br0">&#40;</span><span class="st_h">'name'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span> &lt;br /&gt;
  <span class="kw2">&lt;?php</span> <span class="kw1">endif</span><span class="sy0">;</span> <span class="sy1">?&gt;</span>
  Name:    <span class="kw2">&lt;?php</span> <span class="kw1">echo</span> input_tag<span class="br0">&#40;</span><span class="st_h">'name'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>&lt;br /&gt;
  ...
  <span class="kw2">&lt;?php</span> <span class="kw1">echo</span> submit_tag<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
&lt;/form&gt;</pre>

<p>リスト10-23の<code>getError()</code>メソッドを使って条件文を書くのは少し冗長です。<code>Validation</code>ヘルパーグループの使用を宣言することを前提とすると、symfonyが<code>getError()</code>メソッドを置き換えるために<code>form_error()</code>ヘルパーを提供する理由はそういうわけです。リスト10-25はこのヘルパーを使うことでリスト10-24を置き換えています。</p>

<p>リスト10-25 - 省略記法でフォーム内部からエラーメッセージを表示する</p>

<pre class="php"><span class="kw2">&lt;?php</span> use_helper<span class="br0">&#40;</span><span class="st_h">'Validation'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> form_tag<span class="br0">&#40;</span><span class="st_h">'contact/send'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
&nbsp;
           <span class="kw2">&lt;?php</span> <span class="kw1">echo</span> form_error<span class="br0">&#40;</span><span class="st_h">'name'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>&lt;br /&gt;
  名前:    <span class="kw2">&lt;?php</span> <span class="kw1">echo</span> input_tag<span class="br0">&#40;</span><span class="st_h">'name'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>&lt;br /&gt;
  ...
  <span class="kw2">&lt;?php</span> <span class="kw1">echo</span> submit_tag<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
&lt;/form&gt;</pre>

<p><code>form_error()</code>ヘルパーはメッセージをより見やすくするためにそれぞれのエラーメッセージの前後に特別な文字を追加します。デフォルトでは、文字は下を指し示す矢印(<code>&amp;darr;</code>エンティティに対応)ですが、<code>settings.yml</code>ファイルで変更できます:</p>

<pre><code>all:
  .settings:
    validation_error_prefix:    ' &amp;darr;&amp;nbsp;'
    validation_error_suffix:    ' &amp;nbsp;&amp;darr;'
</code></pre>

<p>バリデーションを失敗した場合、フォームはエラーを正しく表示しますが、ユーザーによって入力されたデータは失われます。本当にユーザーフレンドリーにするにはフォームを再投入する必要があります。</p>

<a name="repopulating.the.form" id="repopulating.the.form"></a><h3>フォームを再投入する</h3>

<p>エラー処理は<code>forward()</code>メソッドを通して行われるので(リスト10-21で示される)、オリジナルのリクエストはまだアクセス可能で、ユーザーによって入力されたデータはリクエストパラメーターのなかに存在します。リスト10-26で示されるように、デフォルト値をそれぞれのフィールドに追加することでフォームを再投入できます。</p>

<p>リスト10-26 - バリデーションが失敗したときにフォームを再投入するためにデフォルト値を設定する(<code>templates/indexSuccess.php</code>)</p>

<pre class="php"><span class="kw2">&lt;?php</span> use_helper<span class="br0">&#40;</span><span class="st_h">'Validation'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> form_tag<span class="br0">&#40;</span><span class="st_h">'contact/send'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
           <span class="kw2">&lt;?php</span> <span class="kw1">echo</span> form_error<span class="br0">&#40;</span><span class="st_h">'name'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>&lt;br /&gt;
  名前:    <span class="kw2">&lt;?php</span> <span class="kw1">echo</span> input_tag<span class="br0">&#40;</span><span class="st_h">'name'</span><span class="sy0">,</span> <span class="re0">$sf_params</span><span class="sy0">-&gt;</span><span class="me1">get</span><span class="br0">&#40;</span><span class="st_h">'name'</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>&lt;br /&gt;
           <span class="kw2">&lt;?php</span> <span class="kw1">echo</span> form_error<span class="br0">&#40;</span><span class="st_h">'email'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>&lt;br /&gt;
  Eメール:   <span class="kw2">&lt;?php</span> <span class="kw1">echo</span> input_tag<span class="br0">&#40;</span><span class="st_h">'email'</span><span class="sy0">,</span> <span class="re0">$sf_params</span><span class="sy0">-&gt;</span><span class="me1">get</span><span class="br0">&#40;</span><span class="st_h">'email'</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>&lt;br /&gt;
           <span class="kw2">&lt;?php</span> <span class="kw1">echo</span> form_error<span class="br0">&#40;</span><span class="st_h">'age'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>&lt;br /&gt;
  年齢:     <span class="kw2">&lt;?php</span> <span class="kw1">echo</span> input_tag<span class="br0">&#40;</span><span class="st_h">'age'</span><span class="sy0">,</span> <span class="re0">$sf_params</span><span class="sy0">-&gt;</span><span class="me1">get</span><span class="br0">&#40;</span><span class="st_h">'age'</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>&lt;br /&gt;
           <span class="kw2">&lt;?php</span> <span class="kw1">echo</span> form_error<span class="br0">&#40;</span><span class="st_h">'message'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>&lt;br /&gt;
  メッセージ: <span class="kw2">&lt;?php</span> <span class="kw1">echo</span> textarea_tag<span class="br0">&#40;</span><span class="st_h">'message'</span><span class="sy0">,</span> <span class="re0">$sf_params</span><span class="sy0">-&gt;</span><span class="me1">get</span><span class="br0">&#40;</span><span class="st_h">'message'</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>&lt;br /&gt;
  <span class="kw2">&lt;?php</span> <span class="kw1">echo</span> submit_tag<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
&lt;/form&gt;</pre>

<p>繰り返しますが、これを書く作業はとても退屈です。YAMLバリデーションファイルにおいて、symfonyは要素のデフォルト値を変更せずにフォームのすべてのフィールドを再投入する代替方法を提供します。フォームに対して<code>fillin:</code>機能を有効にするだけです。構文はリスト10-27で説明されています。</p>

<p>リスト10-27 - バリデーションが失敗したときにフォームを再投入するために<code>fillin</code>を有効にする(<code>validate/send.yml</code>)</p>

<pre><code>fillin:
  enabled: true  # フォームの再投入を有効にする
  param:
    name: test  # ページに1つのフォームのみが存在する場合のフォーム名
    skip_fields:   [email]  # これらのフィールドを再投入しない
    exclude_types: [hidden, password] # これらのフィールドタイプを再投入しない
    check_types:   [text, checkbox, radio, password, hidden] # これらを再投入する
    content_type:  html  # htmlは寛容なデフォルト。ほかのオプションはxmlとxhtml(xmlと同じだがxmlの最初の部分はなし)
</code></pre>

<p>デフォルトでは、自動の再投入はテキスト入力、チェックボックス、ラジオボタン、テキストエリアと選択コンポーネント(シンプルなものと複数)に対して動作しますが、パスワードもしくは隠しタグは再投入しません。<code>fillin</code>機能はファイルタグに対して動作しません。</p>

<blockquote class="note"><p>
  <code>fillin</code>機能はXMLのレスポンスの内容をユーザーに送信するに解析することで機能します。デフォルトでは<code>fillin</code>はHTMLを出力します。</p>
  
  <p><code>fillin</code>にXHTMLを出力させたい場合、<code>param: content_type: xml</code>を設定しなければなりません。レスポンスが厳密に有効なXHTMLドキュメントではない場合<code>fillin</code>は機能しません。
  3番目に利用可能な<code>content_type</code>は<code>xhtml</code>で<code>xml</code>と同じですがIE6で奇妙な動作を引き起こすレスポンスからxmlのプロローグをとり除きます。</p>
</blockquote>

<p>ユーザーが入力した値をフォームの入力に書き戻すまえにこれらを変換したい場合があります。リスト10-28で示されるように、<code>conveters:</code>キーの下で変換方法を定義すればエスケーピング、URLの書き換え、特別な文字をエンティティに変換する、関数を通して呼び出されたほかの変換などはフォームのフィールドに適用できます。</p>

<p>リスト10-28 - <code>fillin</code>のまえに入力を変換する(<code>validate/send.yml</code>)</p>

<pre><code>fillin:
  enabled: true
  param:
    name: test
    converters:         # 適用するコンバータ
      htmlentities:     [first_name, comments]
      htmlspecialchars: [comments]
</code></pre>

<a name="standard.symfony.validators" id="standard.symfony.validators"></a><h3>symfonyの標準バリデーター</h3>

<p>symfonyはフォーム用の標準バリデーターをいくつか備えています:</p>

<ul>
<li><code>sfStringValidator</code></li>
<li><code>sfNumberValidator</code></li>
<li><code>sfEmailValidator</code></li>
<li><code>sfUrlValidator</code></li>
<li><code>sfRegexValidator</code></li>
<li><code>sfCompareValidator</code></li>
<li><code>sfPropelUniqueValidator</code></li>
<li><code>sfDoctrineUniqueValidator</code></li>
<li><code>sfFileValidator</code></li>
<li><code>sfCallbackValidator</code></li>
<li><code>sfDateValidator</code></li>
</ul>

<p>それぞれのバリデーターはデフォルトのパラメーターとエラーメッセージのセットを持ちますが、
YAMLファイルのなかで、<code>initialize()</code>バリデーターメソッドを通して簡単にオーバーライドできます。
つぎのセクションでバリデーターを説明し、使いかたの例を示します。</p>

<a name="string.validator" id="string.validator"></a><h4>文字列バリデーター</h4>

<p><code>sfStringValidator</code>によって文字に関連する制約をパラメーターに適用できるようになります。</p>

<pre><code>sfStringValidator:
  values:       [foo, bar]
  values_error: 認められる値はfooとbarのみです
  insensitive:  false  # trueの場合、値との比較は大文字と小文字を区別しない
  min:          2
  min_error:    少なくとも2文字入力してください
  max:          100
  max_error:    100文字以下で入力してください
</code></pre>

<a name="number.validator" id="number.validator"></a><h4>数字バリデーター</h4>

<p><code>sfNumberValidator</code>パラメーターが数字であることをバリデートし、これによってサイズの制約を適用することができます。</p>

<pre><code>sfNumberValidator:
  nan_error:    整数を入力してください
  min:          0
  min_error:    値は最少で0でなければなりません
  max:          100
  max_error:    値は100以下でなければなりません
</code></pre>

<a name="email.validator" id="email.validator"></a><h4>Eメールバリデーター</h4>

<p><code>sfEmailValidator</code>はEメールアドレスとして有効なパラメーターが含まれるかをバリデートします。</p>

<pre><code>sfEmailValidator:
  strict:       true
  email_error:  このEメールアドレスは無効です
</code></pre>

<p>RFC822はEメールアドレスのフォーマットを定義します。しかしながら、これは一般的に受け入れられるフォーマットよりも寛容です。たとえば、RFCに従えば<code>me@localhost</code>は有効なEメールアドレスですが、おそらくは受信したくないでしょう。<code>strict</code>パラメーターを<code>true</code>にセットするとき、<code>name@domain.extenison</code>にマッチするEメールアドレスだけが有効です。<code>false</code>にセットしするとき、RFC822がルールとして使われます。</p>

<a name="url.validator" id="url.validator"></a><h4>URLバリデーター</h4>

<p><code>sfUrlValidator</code>はフィールドが正しいURLであるかチェックします。</p>

<pre><code>sfUrlValidator:
  url_error:    このURLは無効です
</code></pre>

<a name="regular.expression.validator" id="regular.expression.validator"></a><h4>正規表現バリデーター</h4>

<p><code>sfRegexValidator</code>によって値をPerlと互換性のある正規表現のパターンでチェックできます。</p>

<pre><code>sfRegexValidator:
  match:        No
  match_error:  URLを含む投稿はスパムと見なされます
  pattern:      /http.*http/si
</code></pre>

<p><code>match</code>パラメーターはリクエストパラメーターが有効なパターンにマッチする(値は<code>Yes</code>)、もしくは無効なパターン(値は<code>No</code>)にマッチするかを決定します。</p>

<a name="compare.validator" id="compare.validator"></a><h4>比較バリデーター</h4>

<p><code>sfCompareValidator</code>は2つの異なるリクエストパラメーターを比較します。パスワードをチェックするためにとても便利です。</p>

<pre><code>fields:
  password1:
    required:
      msg:      パスワードを入力してください
  password2:
    required:
      msg:      パスワードを再入力してください
    sfCompareValidator:
      check:    password1
      compare_error: 2つのパスワードが一致しません
</code></pre>

<p><code>check</code>パラメーターは現在のフィールドがマッチしなければならないフィールドの名前を含みます。</p>

<p>デフォルトでは、バリデーターはパラメーターが等しいことをチェックします。<code>operator</code>パラメーターを指定することでこのふるまいを変更できます。利用可能な演算子はつぎのとおりです: <code>&gt;</code>、<code>&gt;=</code>、<code>&lt;</code>、<code>&lt;=</code>、<code>==</code>と<code>!=</code>。</p>

<a name="propel/doctrine.unique.validators" id="propel/doctrine.unique.validators"></a><h4>Propel/Doctrine独自のバリデーター</h4>

<p><code>sfPropelUniqueValidator</code>はすでにリクエストパラメーターの値がデータベースに存在していないかをバリデートします。ユニークインデックスのためにとても便利です。</p>

<pre><code>fields:
  nickname:
    sfPropelUniqueValidator:
      class:        User
      column:       login
      unique_error: このログインはすでに存在します。別のものを入力してください。
</code></pre>

<p>この例において、バリデーターは<code>login</code>カラムがバリデートするフィールドと同じ値を持つ<code>User</code>クラスのレコードに対してデータベースを調べます。</p>

<blockquote class="caution"><p>
  <code>sfPropelUniqueValidator</code>は競合条件の影響を受けやすいです。想像しにくいですが、複数ユーザーの環境において、結果は自身が返す瞬間を変えることがあります。重複の<code>INSERT</code>エラーを処理する準備もすべきです。</p>
</blockquote>

<p>-</p>

<blockquote class="note"><p>
  プロジェクト用にDoctrine ORMを有効にした場合、上記のPropel用に説明した同じ方法で
  <code>sfDoctrineUniqueValidator</code>を使うこともできます。</p>
</blockquote>

<a name="file.validator" id="file.validator"></a><h4>ファイルバリデーター</h4>

<p><code>sfFileValidator</code>はファイルのアップロードフィールドにフォーマット(mime-typeの配列)とサイズの制限を適用します。</p>

<pre><code>fields:
  image:
    file:       True
    required:
      msg:      画像ファイルをアップロードしてください
    sfFileValidator:
      mime_types:
        - 'image/jpeg'
        - 'image/png'
        - 'image/x-png'
        - 'image/pjpeg'
      mime_types_error: PNGとJPEGの画像のみ許可されます
      max_size:         512000
      max_size_error:   最大のサイズは512KBです
</code></pre>

<p>フィールドに対して<code>file</code>属性は<code>True</code>に設定され、テンプレートはフォームをmultipartとして宣言しなければならないことを覚えておいてください。</p>

<a name="callback.validator" id="callback.validator"></a><h4>コールバックバリデーター</h4>

<p><code>sfCallbackValidator</code>はバリデーションをサードパーティのコールバックメソッドもしくはバリデーションを行う関数に委譲します。コールバックメソッドもしくは関数は<code>true</code>もしくは<code>false</code>を返さなければなりません。</p>

<pre><code>fields:
  account_number:
    sfCallbackValidator:
      callback:      is_numeric
      invalid_error: 数字を入力してください。
  credit_card_number:
    sfCallbackValidator:
      callback:      [myTools, validateCreditCard]
      invalid_error: 有効なクレジットカードの番号を入力してください。
</code></pre>

<p>コールバックメソッドもしくは関数はバリデートされた値を最初のパラメーターとして受けとります。新しい完全なバリデータークラスを作成するよりも、既存のメソッドの機能を再利用するときにとても役立ちます。</p>

<blockquote class="tip"><p>
  この章の後のほうの"カスタムバリデーターを作成する"のセクションで説明されている独自のバリデーターを書くこともできます。</p>
</blockquote>

<a name="date.validator" id="date.validator"></a><h4>日付バリデーター</h4>

<p><code>sfDateValidator</code>は投稿された日付が有効かつ/もしくは指定範囲にあることをチェックします。</p>

<pre><code>sfDateValidator:
  date_error:    You have entered an invalid date
  compare:       "2007-05-01"
  operator:      "&gt;="  #defaults to "==" if not supplied
  compare_error: "Enter a date later than 1st May 2007"
</code></pre>

<blockquote class="tip"><p>
  この章の後の"カスタムバリデーターを作成する"のセクションで説明されているように、独自バリデーターを書くこともできます。</p>
</blockquote>

<a name="named.validators" id="named.validators"></a><h3>名前つきバリデーター</h3>

<p>バリデータークラスと設定を繰り返す必要があることがわかっている場合、これを名前つきバリデーターのもとでまとめることができます。連絡フォームの例において、emailフィールドは同じ<code>sfStringValidator</code>パラメーターを<code>name</code>フィールドとして必要とします。同じ設定を2回繰り返すことを避けるために、名前つきのバリデーターである<code>myStringValidator</code>を作成できます。これを行うために、<code>myStringValidator</code>ラベルを<code>validators:</code>ヘッダーの下に追加し、まとめたい名前つきのバリデーターの詳細な内容を持つ<code>class</code>キーと<code>param</code>キーを設定します。リスト10-29で示されるように、<code>fields</code>セクションの通常の名前つきバリデーターとまったく同じように、名前つきバリデーターを利用できます。</p>

<p>リスト10-29 - バリデーションファイルで名前つきバリデーターを再利用する(<code>validte/send.yml</code>)</p>

<pre><code>validators:
  myStringValidator:
    class: sfStringValidator
    param:
      min:       2
      min_error: このフィールドは短すぎます(最少で2文字)
      max:       100
      max_error: このフィールドは長すぎます(最大で100文字)

fields:
  name:
    required:
      msg:       名前のフィールドは空白であってはなりません
    myStringValidator:
  email:
    required:
      msg:       Eメールのフィールドは空白であってはなりません
    myStringValidator:
    sfEmailValidator:
      email_error:  このEメールは無効です
</code></pre>

<a name="restricting.the.validation.to.a.method" id="restricting.the.validation.to.a.method"></a><h3>メソッドへのバリデーションを制限する</h3>

<p>デフォルトでは、バリデーションファイルに設定されたバリデーターは、アクションがPOSTメソッドで呼び出されたときに実行されます。リスト10-30で示されるように、異なるメソッドに対して異なるバリデーションをできるようにするために、<code>methods</code>キーで別の値を指定することでこの設定をグローバルもしくはフィールド単位でオーバーライドできます。</p>

<p>リスト10-30 - フィールドをテストするときを定義する(<code>validate/send.yml</code>)</p>

<pre><code>methods:         [post]     # これはデフォルトの設定

fields:
  name:
    required:
      msg:       名前のフィールドは空白にはできません
    myStringValidator:
  email:
    methods:     [post, get] # グローバルメソッドの設定をオーバーライドする
    required:
      msg:       Eメールフィールドは空白にはできません
    myStringValidator:
    sfEmailValidator:
      email_error:  このEメールアドレスは無効です
</code></pre>

<a name="what.does.a.validation.file.look.like" id="what.does.a.validation.file.look.like"></a><h3>バリデーションファイルはどのようになるのか？</h3>

<p>これまでのところ、バリデーションファイルの断片しか見てきませんでした。すべてを組み立てるとき、バリデーションのルールはYAMLで明確な変換を見つけます。リスト10-31はこの章の前の方で定義したすべてのルールに対応するサンプルの問い合わせフォームのための完全なバリデーションファイルを示しています。</p>

<p>リスト10-31 - サンプルの完全なバリデーションファイル</p>

<pre><code>fillin:
  enabled:      true

validators:
  myStringValidator:
    class: sfStringValidator
    param:
      min:       2
      min_error: このフィールドは短すぎます(最少で2文字)
      max:       100
      max_error: このフィールドは長すぎます(最大で100文字)

fields:
  name:
    required:
      msg:       名前のフィールドは空白にはできません
    myStringValidator:
  email:
    required:
      msg:       Eメールフィールドは空白にはできません
    myStringValidator:
    sfEmailValidator:
      email_error:  このEメールアドレスは無効です
  age:
    sfNumberValidator:
      nan_error:    整数を入力してください
      min:          0
      min_error:    "まだあなたは生まれていません。どのようにメッセージを送りたいのですか？"
      max:          120
      max_error:    "ちょっと、おばあちゃん、インターネットをサーフィンするには年をとりすぎていませんか？"
  message:
    required:
      msg:          メッセージフィールドは空白にはできません
</code></pre>

<a name="complex.validation" id="complex.validation"></a><h2>複雑なバリデーション</h2>

<p>バリデーションファイルは多くのニーズを満たしますが、バリデーションがとても複雑なときに十分ではないことがあります。この場合、アクションの<code>validateXXX()</code>メソッドに戻るもしくはつぎのセクションであなたの問題の解決方法が見つかります。</p>

<a name="creating.a.custom.validator" id="creating.a.custom.validator"></a><h3>カスタムバリデーターを作成する</h3>

<p>それぞれのバリデーターは<code>sfValidator</code>クラスを継承するクラスです。symfonyに搭載されたバリデータークラスがあなたのニーズに適していない場合、これをオートロードできる<code>lib/</code>ディレクトリの任意の場所で、新しいバリデータークラスを作成できます。構文はとてもシンプルです: バリデーターが実行されるとき、バリデーターの<code>execute()</code>メソッドが呼び出されます。<code>initialize()</code>メソッドでデフォルト設定を定義することもできます。</p>

<p><code>execute()</code>メソッドは最初のパラメーターとしてバリデートする値と2番目のパラメーターとして投げるエラーメッセージを受けとります。両方の値は参照として渡されるので、メソッドの範囲内からエラーメッセージを修正できます。</p>

<p><code>initialize()</code>メソッドはYAMLファイルからContext Singletonとパラメーターの配列を受けとります。最初に親の<code>sfValidator</code>クラスの<code>initalize()</code>メソッドを呼び出さなければならず、そしてデフォルト値を設定します。</p>

<p>すべてのバリデーターは<code>$this-&gt;getParameterHolder()</code>によってアクセス可能なパラメーターホルダーを持ちます。</p>

<p>たとえば、文字列がスパムではないことをチェックするために<code>sfSpamValidator</code>を作りたい場合、リスト10-32で示されるコードを<code>sfSpamValidator.class.php</code>ファイルを追加します。<code>$value</code>が文字列の<code>'http'</code>を<code>max_url</code>倍多くの含むのかをチェックします。</p>

<p>リスト10-32 - カスタムバリデーターを作成する(<code>lib/sfSpamValidator.class.php</code>)</p>

<pre class="php"><span class="kw2">class</span> sfSpamValidator <span class="kw2">extends</span> sfValidator
<span class="br0">&#123;</span>
  <span class="kw2">public</span> <span class="kw2">function</span> execute<span class="br0">&#40;</span><span class="sy0">&amp;</span><span class="re0">$value</span><span class="sy0">,</span> <span class="sy0">&amp;</span><span class="re0">$error</span><span class="br0">&#41;</span>
  <span class="br0">&#123;</span>
    <span class="co1">// max_url=2に対して、正規表現は/http.*http/is</span>
    <span class="re0">$re</span> <span class="sy0">=</span> <span class="st_h">'/'</span><span class="sy0">.</span><span class="kw3">implode</span><span class="br0">&#40;</span><span class="st_h">'.*'</span><span class="sy0">,</span> <span class="kw3">array_fill</span><span class="br0">&#40;</span><span class="nu0">0</span><span class="sy0">,</span> <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">getParameter</span><span class="br0">&#40;</span><span class="st_h">'max_url'</span><span class="br0">&#41;</span> <span class="sy0">+</span> <span class="nu0">1</span><span class="sy0">,</span> <span class="st_h">'http'</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">.</span><span class="st_h">'/is'</span><span class="sy0">;</span>
&nbsp;
    <span class="kw1">if</span> <span class="br0">&#40;</span><span class="kw3">preg_match</span><span class="br0">&#40;</span><span class="re0">$re</span><span class="sy0">,</span> <span class="re0">$value</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
    <span class="br0">&#123;</span>
      <span class="re0">$error</span> <span class="sy0">=</span> <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">getParameter</span><span class="br0">&#40;</span><span class="st_h">'spam_error'</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
      <span class="kw1">return</span> <span class="kw4">false</span><span class="sy0">;</span>
    <span class="br0">&#125;</span>
&nbsp;
    <span class="kw1">return</span> <span class="kw4">true</span><span class="sy0">;</span>
  <span class="br0">&#125;</span>
&nbsp;
  <span class="kw2">public</span> <span class="kw2">function</span> initialize <span class="br0">&#40;</span><span class="re0">$context</span><span class="sy0">,</span> <span class="re0">$parameters</span> <span class="sy0">=</span> <span class="kw4">null</span><span class="br0">&#41;</span>
  <span class="br0">&#123;</span>
    <span class="co1">// 親を初期化する</span>
    parent<span class="sy0">::</span><span class="me2">initialize</span><span class="br0">&#40;</span><span class="re0">$context</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
    <span class="co1">// パラメーターのデフォルト値を設定する</span>
    <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">setParameter</span><span class="br0">&#40;</span><span class="st_h">'max_url'</span><span class="sy0">,</span> <span class="nu0">2</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">setParameter</span><span class="br0">&#40;</span><span class="st_h">'spam_error'</span><span class="sy0">,</span> <span class="st_h">'This is spam'</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
    <span class="co1">// パラメーターを設定する</span>
    <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">getParameterHolder</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me1">add</span><span class="br0">&#40;</span><span class="re0">$parameters</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
    <span class="kw1">return</span> <span class="kw4">true</span><span class="sy0">;</span>
  <span class="br0">&#125;</span>
<span class="br0">&#125;</span></pre>

<p>バリデーターが<code>autoloadable</code>ディレクトリに追加されると同時に(そしてキャッシュがクリアされる)、リスト10-33で示されるように、バリデーションファイルでこれを使うことができます。</p>

<p>リスト10-33 - カスタムバリデーターを使う(<code>validate/send.yml</code>)</p>

<pre><code>fields:
  message:
    required:
      msg:          メッセージフィールドを空白にできません
    sfSpamValidator:
      max_url:      3
      spam_error:   このサイトを立ち去ってください、汚らわしいスパマーさん！
</code></pre>

<a name="using.array.syntax.for.form.fields" id="using.array.syntax.for.form.fields"></a><h3>フォームフィールドに対して配列構文を使う</h3>

<p>PHPによってフォームフィールドに対して配列構文を利用できます。独自のフォームを書くとき、もしくはPropelのadministration(14章を参照)の生成フォームを使うとき、リスト10-34のようなHTMLのコードで終わります。</p>

<p>リスト10-34 - 配列構文によるフォーム</p>

<pre class="php"><span class="sy0">&lt;</span>label <span class="kw1">for</span><span class="sy0">=</span><span class="st0">&quot;story_title&quot;</span><span class="sy0">&gt;</span>タイトル<span class="sy0">:&lt;/</span>label<span class="sy0">&gt;</span>
<span class="sy0">&lt;</span>input type<span class="sy0">=</span><span class="st0">&quot;text&quot;</span> name<span class="sy0">=</span><span class="st0">&quot;story[title]&quot;</span> id<span class="sy0">=</span><span class="st0">&quot;story_title&quot;</span> value<span class="sy0">=</span><span class="st0">&quot;default value&quot;</span>
       size<span class="sy0">=</span><span class="st0">&quot;45&quot;</span> <span class="sy0">/&gt;</span></pre>

<p>バリデーションファイルで入力名を(角かっこで)そのまま使うと解析で引き起こされたエラーが投じられます。ここでの解決方法はリスト10-35で示されるように、<code>fields</code>セクションにおいて、角かっこ<code>[]</code>を波かっこ<code>{}</code>で置き換えることで、symfonyはあとでバリデーターに送られる名前の変換を考慮するようになります。</p>

<p>リスト10-35 - 配列構文を使ったフォームのためのバリデーションファイル</p>

<pre><code>fields:
  story{title}:
    required:     Yes
</code></pre>

<a name="executing.a.validator.on.an.empty.field" id="executing.a.validator.on.an.empty.field"></a><h3>空のフィールド上でバリデーターを実行する</h3>

<p>空の値の上で、必要ないフィールド上で、バリデーターを実行することが必要な場合があります。たとえば、ユーザーがパスワードを変更したい(したくない場合)にこの事例があてはまります。この場合、確認パスワードを入力しなければなりません。リスト10-36で例をご覧ください。</p>

<p>リスト10-36 - 2つのパスワードフィールドを持つフォーム用のバリデーションファイルのサンプル</p>

<pre><code>fields:
  password1:
  password2:
    sfCompareValidator:
      check:         password1
      compare_error: 2つのパスワードが一致しません
</code></pre>

<p>バリデーションの処理はつぎのように実行されます:</p>

<ul>
<li><p><code>password1</code> <code>== null</code>と<code>password2 == null</code>の場合:</p>

<ul>
<li><code>required</code>テストは合格します。</li>
<li>バリデーターは実行されません。</li>
<li>フォームは有効です。</li>
</ul></li>
<li><p><code>password2 == null</code>である一方で<code>password1</code>が<code>null</code>ではない場合:</p>

<ul>
<li><code>required</code>テストは合格します。</li>
<li>バリデーターは実行されません。</li>
<li>フォームは有効です。</li>
</ul></li>
</ul>

<p><code>password1</code>が<code>not null</code>であるかどうか<code>password2</code>バリデーターを実行したい場合があります。幸いにも、<code>group</code>パラメーターのおかげでsymfonyバリデーターはこの事例に対処します。フィールドがグループのなかに存在する場合、それが空ではなく同じグループのフィールドの1つが空ではないかバリデーターを実行します。</p>

<p>ですので、リスト10-36で示されているように設定を変更する場合、バリデーションプロセスは正しくふるまいます。</p>

<p>リスト10-36 - 2つのパスワードフィールドとグループによるフォーム用のバリデーションファイルのサンプル</p>

<pre><code>fields:
  password1:
    group:           password_group
  password2:
    group:           password_group
    sfCompareValidator:
      check:         password1
      compare_error: 2つのパスワードが一致しません
</code></pre>

<p>バリデーションの処理はつぎのように実行します:</p>

<ul>
<li><p><code>password1 == null</code>かつ<code>password2 == null</code>の場合:</p>

<ul>
<li><code>required</code>のテストは合格します。</li>
<li>バリデーターは実行されません。</li>
<li>フォームは有効です。</li>
</ul></li>
<li><p><code>password1 == null</code>かつ<code>password2 == 'foo'</code>の場合:</p>

<ul>
<li><code>required</code>テストは合格します。</li>
<li><code>password2</code>は<code>not null</code>なので、バリデーターは実行され、失敗します。</li>
<li>エラーメッセージが<code>password2</code>に投げられます。</li>
</ul></li>
<li><p><code>password1 == 'foo'</code>で<code>password2 == null</code>の場合:</p>

<ul>
<li><code>required</code>テストは合格します。</li>
<li><code>password1</code>が<code>not null</code>なので同じグループにある<code>password2</code>のためのバリデーターが実行され、失敗します。</li>
<li>エラーメッセージが<code>password2</code>に投げられます。</li>
</ul></li>
<li><p><code>password1 == 'foo'</code>で<code>password2 == 'foo'</code>の場合:</p>

<ul>
<li><code>required</code>テストは合格します。</li>
<li><code>password2</code>が<code>not null</code>なので、バリデーターが実行され、合格します。</li>
<li>フォームは有効です。</li>
</ul></li>
</ul>

<a name="summary" id="summary"></a><h2>まとめ</h2>

<p>symfonyのテンプレートのなかでフォーム(form)を書く作業は標準のフォームヘルパーとスマートなオプションによって円滑になります。オブジェクトのプロパティを編集するためにフォームを設計するとき、バリデーションファイル(validation file)、バリデーションヘルパー、と再投入機能は頑強でユーザーフレンドリーなサーバーのフィールド値コントロール機能を開発するために必要な作業量を減らします。そして、アクションクラスのなかでカスタムバリデーターを書くもしくは<code>validateXXX()</code>メソッドを作ることで、より複雑なバリデーションのニーズに対応することができます。</p>
</div>
<div class="navigation">
<hr/>
<table width="100%">
<tr>
<td width="40%" align="left"><a href="09-Links-and-the-Routing-System.html">前の章</a></td>
<td width="20%" align="center"><a href="index.html">ホーム</a></td>
<td width="40%" align="right"><a href="11-Ajax-Integration.html">次の章</a></td>
</tr>
</table>

</div>
</body>

</html>
